必威体育Betway必威体育官网
当前位置:首页 > IT技术

异步I/O(一)

时间:2019-11-01 01:15:33来源:IT技术作者:seo实验室小编阅读:70次「手机版」
 

异步io

异步I/O(一)

概述

aiO可以一次性发出大量的read/write调用并且通过通用块层的IO调度来获得更好的性能,用户程序也可以减少过多的同步负载,还可以在业务逻辑中更灵活的进行并发控制和负载均衡

POSIX异步I/O(AIO)接口允许应用程序启动一个或多个异步执行的I/O操作。应用程序可以选择以各种方式通知I/O操作的完成:通过传递信号,通过实例化线程或运行完后没有通知。

控制块缓冲区和aio_buf指向的缓冲区在I / O操作正在进行时不能改变。 这些缓冲区必须保持有效,直到I / O操作完成。

使用相同的aiocb结构同时进行异步读取或写入操作会产生未定义的结果。

当前的linux POSIX AIO实现由glibc在用户空间中提供。 这具有许多局限性,最值得注意的是维护多个线程来执行I / O操作是昂贵的,并且规模很小。 基于状态机的异步I / O实现(参见io_submit(2),io_setup(2),io_cancel(2),io_destroy(2),io_getevents(2))已经有一段时间了, 但是这种实现还没有成熟到POSIX AIO实现可以使用内核系统调用完全重新实现的程度。

异步I/O相关接口

POSIXAIO接口由以下功能组成

aio_read排队读取请求。这是read函数的异步模拟。

aio_write排队写入请求。这是write函数的异步模拟。

aio_fsync为文件描述符上的I/O操作排队同步请求。这是fsync和fdatasync的异步模拟。

aio_ERROR获取入队I/O请求的错误状态。

aio_return获取完成的I/O请求的返回状态。

aio_suspend挂起调用者,直到一个或多个指定的I/O请求完成。

aio_cancel尝试取消指定文件描述符上的未完成I/O请求。

        lio_listio使用单个函数调用排队多个I/O请求。

重要的数据结构

aiocb(“异步I/O控制块”)结构定义了控制I/O操作的参数。这种类型的论点被用于上面列出的所有功能。该结构主要的成员如下:

#include<aiocb.h>

structaiocb{

       

        intaio_fildes;/*文件描述符*/

        off_taio_offset;/*文件偏移*/

        volatilevoid*aio_buf;/*缓冲区的位置*/

        size_taio_nbytes;/*传输长度*/

        intaio_reqprio;/*请求优先权*/

        structsigeventaio_sigevent;/*通知方式*/

        intaio_lio_opcode;/*要执行的操作;lio_listio()only*/

};

/*'aio_lio_opcode'的操作码:*/

enum{LIO_READ,LIO_WRITE,LIO_NOP};

测试例子及说明

文件拷贝-阻塞+缓存版本

#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define BSZ 4096

unsigned char buf[BSZ];

#define FILE_MODE       (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char* argv[])
{
        int     ifd, ofd, i, n, nw;

        if (argc != 3){
                printf("usage: cp infile outfile");
                exit(-1);

        }

        if ((ifd = open(argv[1], O_RDONLY)) < 0){
                printf("can't open %s", argv[1]);
                exit(-1);

        }

        if ((ofd = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, FILE_MODE)) < 0){
                printf("can't create %s", argv[2]);
                exit(-1);

        }

        while ((n = read(ifd, buf, BSZ)) > 0) {
                if ((nw = write(ofd, buf, n)) != n) {
                       if (nw < 0){
                                printf("write failed"); 
                                exit(-1);

                        }else{
                                printf("short write (%d/%d)", nw, n);
                                exit(-1);
                        }
                }
        }


        fsync(ofd);
        exit(0);

}

异步IO拷贝文件版本

#include <ctype.h>
#include <fcntl.h>
#include <aio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define BSZ 4096
#define NBUF 4
#define FILE_MODE       (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

enum rwop {
        UNUSED = 0,
        READ_PENDING = 1,
        WRITE_PENDING = 2
};

struct buf {
        enum rwop     op;
        int           last;
        struct aiocb  aiocb;
        unsigned char data[BSZ];
};

struct buf bufs[NBUF];
int main(int argc, char* argv[])
{

        int                                     ifd, ofd, i,  n, err, numop;
        struct stat                     sbuf;
        const struct aiocb      *aiolist[NBUF];
        off_t                           off = 0;

        if (argc != 3){
                printf("usage: cp infile outfile");
                exit(-1);
        }

        if ((ifd = open(argv[1], O_RDONLY)) < 0){
                printf("can't open %s", argv[1]);
                exit(-1);

        }

        if ((ofd = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, FILE_MODE)) < 0){
                printf("can't create %s", argv[2]);
                exit(-1);
        }

        if (fstat(ifd, &sbuf) < 0){
                printf("fstat failed");
                exit(-1);
        }



        /* initialize the buffers */
        for (i = 0; i < NBUF; i++) {
                bufs[i].op = UNUSED;
                bufs[i].aiocb.aio_buf = bufs[i].data;
                bufs[i].aiocb.aio_sigevent.sigev_notify = SIGEV_NONE;
                aiolist[i] = NULL;
        }



        numop = 0;
        for (;;) {
                for (i = 0; i < NBUF; i++) {
                        switch (bufs[i].op) {
                        case UNUSED:
                                /*
                                 * Read from the input file if more data
                                 */

                                if (off < sbuf.st_size) {
                                        bufs[i].op = READ_PENDING;
                                        bufs[i].aiocb.aio_fildes = ifd;
                                        bufs[i].aiocb.aio_offset = off;
                                        off += BSZ;
                                        if (off >= sbuf.st_size)
                                                bufs[i].last = 1;
                                        bufs[i].aiocb.aio_nbytes = BSZ;
                                        if (aio_read(&bufs[i].aiocb) < 0){
                                                printf("aio_read failed");
                                                exit(-1);
                                        }
                                        aiolist[i] = &bufs[i].aiocb;

                                        numop++;

                                }

                                break;

                        case READ_PENDING:

                                if ((err = aio_error(&bufs[i].aiocb)) == einprogress)

                                        continue;

                                if (err != 0) {

                                        if (err == -1){
                                                printf("aio_error failed");
                                                exit(-1);

                                        }else{
                                                printf("%s\n", "read failed");
                                                exit(-1);
                                        }
                                }

                                /*
                                 * A read is complete and write it.
                                 */

                                if ((n = aio_return(&bufs[i].aiocb)) < 0)
                                        printf("aio_return failed");

                                if (n != BSZ && !bufs[i].last)
                                        printf("short read (%d/%d)", n, BSZ);
                                bufs[i].op = WRITE_PENDING;
                                bufs[i].aiocb.aio_fildes = ofd;
                                bufs[i].aiocb.aio_nbytes = n;
                                if (aio_write(&bufs[i].aiocb) < 0){
                                        printf("aio_write failed");     
                                        exit(-1);
                                }

                                break;

                        case WRITE_PENDING:
                                if ((err = aio_error(&bufs[i].aiocb)) == EINPROGRESS)
                                        continue;
                                if (err != 0) {
                                        if (err == -1){
                                                printf("aio_error failed");
                                                exit(-1);
                                        }else{
                                                printf("%s", "write failed");
                                                exit(-1);
                                        }
                                }
                                /*
                                 * A write is complete; 
                                 */

                                if ((n = aio_return(&bufs[i].aiocb)) < 0)
                                        printf("aio_return failed");
                                if (n != bufs[i].aiocb.aio_nbytes)
                                        printf("short write (%d/%d)", n, BSZ);

                                aiolist[i] = NULL;
                                bufs[i].op = UNUSED;
                                numop--;
                                break;

                        }
                }

                if (numop == 0) {
                        if (off >= sbuf.st_size)
                                break;
                } else {
                        if (aio_suspend(aiolist, NBUF, NULL) < 0){
                                printf("aio_suspend failed");
                                exit(-1);
                        }
                }
        }



        bufs[0].aiocb.aio_fildes = ofd;
        if (aio_fsync(O_SYNC, &bufs[0].aiocb) < 0){
                printf("aio_fsync failed");
                exit(-1);
        }

        exit(0);

}

运行说明

[root@bogon root]# time ./cp2  /etc/services 1

real    0m0.033s

user    0m0.001s

sys     0m0.007s

[root@bogon root]# time ./cp1 /etc/services 1

real    0m0.017s

user    0m0.000s

sys     0m0.004s

从上面的运行结果可以看出异步IO运行时间比阻塞+缓存版本的事件长。原因是异步IO需要更多的同步时间。可以运行strace命令查看。具体情况如下所示

阻塞+缓存版本strace如下:

strace -c ./cp  /etc/services 1

% time     seconds  usecs/call     calls    errors syscall

------ ----------- ----------- --------- --------- ----------------

33.92    0.001592          10       164           write

32.59    0.001530           9       168           read

19.47    0.000914         152         6           open

10.18    0.000478         478         1           fsync

1.51    0.000071           9         8           mprotect

1.07    0.000050           4        13           mmap

0.51    0.000024          24         1           munmap

0.17    0.000008           4         2           rt_sigaction

0.11    0.000005           1         4           fstat

0.11    0.000005           5         1           arch_prctl

0.09    0.000004           1         4           close

0.09    0.000004           4         1           getrlimit

0.06    0.000003           3         1           rt_sigprocmask

0.06    0.000003           3         1           set_tid_address

0.06    0.000003           3         1           set_robust_list

0.00    0.000000           0         1           brk

0.00    0.000000           0         1         1 access

0.00    0.000000           0         1           execve

------ ----------- ----------- --------- --------- ----------------

100.00    0.004694                   379         1 total

异步IO版本strace如下:

[root@bogon advio]# strace -c ./cp /etc/services 1

% time     seconds  usecs/call     calls    errors syscall

------ ----------- ----------- --------- --------- ----------------

86.53    0.005877           9       685         1 futex

6.63    0.000450          75         6           open

2.03    0.000138           9        15           mmap

1.59    0.000108          11        10           mprotect

0.66    0.000045          23         2           clone

0.34    0.000023          23         1           munmap

0.32    0.000022           4         5           fstat

0.32    0.000022           4         5           rt_sigprocmask

0.31    0.000021           5         4           brk

0.25    0.000017           6         3           read

0.24    0.000016           4         4           close

0.19    0.000013          13         1         1 access

0.13    0.000009           5         2           rt_sigaction

0.07    0.000005           5         1           execve

0.06    0.000004           4         1           getrlimit

0.06    0.000004           4         1           sched_getparam

0.06    0.000004           4         1           sched_getscheduler

0.06    0.000004           4         1           arch_prctl

0.06    0.000004           4         1           set_tid_address

0.04    0.000003           3         1           fcntl

0.04    0.000003           3         1           set_robust_list

------ ----------- ----------- --------- --------- ----------------

100.00    0.006792                   751         2 total

从上可以看出来异步IO很多的时间都花在了futex同步上了。

参考资料

[1].http://blog.sina.com.cn/s/blog_6f55491501016diq.html

[2]. http://www.wzxue.com/linux-kernel-aio这个奇葩

[3]. http://man7.org/linux/man-pages/man7/aio.7.html 

文章最后发布于: 2018-06-11 00:05:33

相关阅读

中小企业如何通过SEO优化推广产品并获得订单?

根据市场来看,目前中小企业如果能把SEO优化做好,那么在网络上获取订单的机会是很大的。但是要如何通过网站优化推广产品,并获得订单

offsetWidth等等的介绍

最近弄了一个放大镜的案例,所以在这里写了一下关于dom中offsetWidth等相关属性 给个图,大家体验下 有兴趣的可以自己去试下 <!DOC

PID算法

今天在写文档时看见流程图中有PID算法,莫名熟悉,查了下是过程控制算法,对不起大学自动控制理论的老师-_-!PID算法在过程控制中,按偏差

404页面(404 not found)的解决方法

平头哥SEO在浏览某网页的时候突然跳出提示 404 not found,这可着实惊呆了平头哥了,404 not found是什么意思呢?该怎么解决呢 ?404 not

location reload页面实现跳转和刷新

  1 history.go(0)2 location.reload()3 location=location4 location.assign(location)5 document.execCommand('Refresh')6

分享到:

栏目导航

推荐阅读

热门阅读