标准库I/O vs linux api I/O全面比较 系列2-------POSIX通用异步库AIO(1)
2013-10-30 14:57
537 查看
比较基础的部分 我就不表示了 比如怎么用aio_read(),aio_write() aio_erro() aio_return() 具体可以man aio_read (你懂的)
下面我们主要是来分析这个AIO库在做一个通用程序时 到底做了什么动作,这些动作到底给你所带来的系统有什么好处?
也只是做一个比较肤浅的分析:
先帖一个简单的代码:【也不知道怎么弄代码片段 直接复制吧】
1 #include <stdio.h>
2 #include <aio.h>
3 #include <fcntl.h>
4 #include <string.h>
5 #include <errno.h>
6 #define BUFFSIZE 1024
7 int main()
8 {
9 int fd;
10 int ret;
11 struct aiocb test_aio;
12 if((fd=open("test.txt",O_RDONLY))==-1)printf("open wrong");
13 memset(&test_aio,0,sizeof(struct aiocb));
14 test_aio.aio_buf=malloc(sizeof(char)*BUFFSIZE);
15 test_aio.aio_fildes=fd;
16 test_aio.aio_nbytes=BUFFSIZE;
17 test_aio.aio_offset=0;
18 if((ret=aio_read(&test_aio))<0)
19 printf("wrong aio_read");
20 //这种是一直在等待中 让其一直在忙等待中
21 while(aio_error(&test_aio)==EINPROGRESS);
22 if((ret=aio_return(&test_aio))>0)
23 {
24
25 printf("异步读取数据已经成功!\n");
26 printf("%s",test_aio.aio_buf);
27 }
28 else
29 printf("异步读取数据失败!");
30
31 }
可以看到这个其实是一个很简单的数据读取到内存中来。我们用strace -f ./a.out 做一个查询,看下系统在接受这个可执行程序之后都做了什么动作:
toms@toms-Vostro-260s:~/C_C++_TEST$ strace -f ./a.out
execve("./a.out", ["./a.out"], [/* 47 vars */]) = 0
brk(0) = 0x9e3e000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb779b000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=100835, ...}) = 0
mmap2(NULL, 100835, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7782000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3 -------------------------------------- (1)
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\31\0\0004\0\0\0"..., 512) = 512-----------------(2)
fstat64(3, {st_mode=S_IFREG|0644, st_size=30696, ...}) = 0
mmap2(NULL, 33352, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7779000
mmap2(0xb7780000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6) = 0xb7780000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\232\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1770984, ...}) = 0
mmap2(NULL, 1780508, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75c6000
mmap2(0xb7773000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ad) = 0xb7773000
mmap2(0xb7776000, 11036, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7776000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320[\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=124637, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75c5000
mmap2(NULL, 107008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75aa000
mmap2(0xb75c1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16) = 0xb75c1000
mmap2(0xb75c3000, 4608, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb75c3000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75a9000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75a96c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7773000, 8192, PROT_READ) = 0
mprotect(0xb75c1000, 4096, PROT_READ) = 0
mprotect(0xb7780000, 4096, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb77be000, 4096, PROT_READ) = 0
munmap(0xb7782000, 100835) = 0
set_tid_address(0xb75a9728) = 3811
set_robust_list(0xb75a9730, 0xc) = 0
futex(0xbfaf3604, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, b75a96c0) = -1 EAGAIN (Resource temporarily unavailable)
rt_sigaction(SIGRTMIN, {0xb75af5f0, [], SA_SIGINFO}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0xb75af680, [], SA_RESTART|SA_SIGINFO}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
uname({sys="Linux", node="toms-Vostro-260s", ...}) = 0
open("test.txt", O_RDONLY) = 3
brk(0) = 0x9e3e000
brk(0x9e5f000) = 0x9e5f000
sched_getparam(3811, { 0 }) = 0
sched_getscheduler(3811) = 0 (SCHED_OTHER)
rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], [], 8) = 0
mmap2(NULL, 27520, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xb7794000
mprotect(0xb7794000, 4096, PROT_NONE) = 0
clone(Process 3812 attached-----------------------------------------------------------------------------------------(3)
child_stack=0xb7799fe4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb779a728, {entry_number:6, base_addr:0xb779a6c0, limit:1048575, seg_32bit:1, contents:0,
read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb779a728) = 3812
[pid 3811] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid 3812] set_robust_list(0xb779a730, 0xc) = 0
[pid 3812] pread64(3, "hello \347\254\254\344\270\200\344\270\252linux aio\347\250\213\345\272\217\357\274"..., 1024, 0) = 34 -------------------------------------------------------------------------------------(4)
[pid 3812] getuid32( <unfinished ...>
[pid 3811] fstat64(1, <u
ac93
nfinished ...>
[pid 3812] <... getuid32 resumed> ) = 1000
[pid 3811] <... fstat64 resumed> {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
[pid 3812] rt_sigqueueinfo(3811, SIG_0, {} <unfinished ...>
[pid 3811] mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
[pid 3812] <... rt_sigqueueinfo resumed> ) = 0
[pid 3811] <... mmap2 resumed> ) = 0xb7793000
[pid 3812] gettimeofday( <unfinished ...>
[pid 3811] write(1, "\345\274\202\346\255\245\350\257\273\345\217\226\346\225\260\346\215\256\345\267\262\347\273\217\346\210\220\345\212\237\357\274"..., 34异步读取数据已经成功!
<unfinished ...>
[pid 3812] <... gettimeofday resumed> {1383114881, 327461}, NULL) = 0
[pid 3811] <... write resumed> ) = 34
[pid 3812] clock_gettime(CLOCK_REALTIME, <unfinished ...>
[pid 3811] write(1, "hello \347\254\254\344\270\200\344\270\252linux aio\347\250\213\345\272\217\357\274"..., 34hello 第一个linux aio程序!
<unfinished ...>
[pid 3812] <... clock_gettime resumed> {1383114881, 327594745}) = 0
[pid 3811] <... write resumed> ) = 34
[pid 3812] futex(0xb77811a4, FUTEX_WAIT_PRIVATE, 1, {0, 999866255} <unfinished ...>
[pid 3811] exit_group(34) = ?
这是一个完整的过程哦 ,可能东西比较多 一步步的来看下:
首先可以看出来 这个pid 有2个进程号 pid 3812 和3811 不往深入分析 本身他就调用了linux本身的创建进程,看过LINUX内核的人应该知道:这里的 (3)调用的是clone. 这个动作就是由aio_read()函数触发的!!
Linux的轻量级进程---就是线程。也就是其本身而言,就是调用Clone一个进程来执行读文件操作,自身进程继续执行,我们在来看上面的调用 ;3182是子进程 3181是父进程。为什么要分析这个呢 ?这个其实对后面的分析aio_read到底做了什么动作是非常重要的。
对于3182而言 :我们执行了(4)也就是我们本身而言,子进程就是异步的一个模拟,同步模拟异步。pread()这个函数是一个阻塞函数哦,pread()本身而言,可能会导致3182的一个阻塞,阻塞完成了I/O 必须通过信号量机制传递。这个信号量在后面有提示的。后面的过程我觉得就比较简单了
也就是说 AIO本身而言 是自己创建线程 用同步来模拟异步哦 表示这样的思路可以用pthread库写一个来模拟异步的传输,下一篇我们就把上面那个代码用pthread线程机制来模拟的代码传上来。
当然本身而言 AIO应该在很多方面做了优化 我仅仅是分析出这个AIO的一个大体的执行流程,然后对以后的分析性能是有帮助的!!
下面我们主要是来分析这个AIO库在做一个通用程序时 到底做了什么动作,这些动作到底给你所带来的系统有什么好处?
也只是做一个比较肤浅的分析:
先帖一个简单的代码:【也不知道怎么弄代码片段 直接复制吧】
1 #include <stdio.h>
2 #include <aio.h>
3 #include <fcntl.h>
4 #include <string.h>
5 #include <errno.h>
6 #define BUFFSIZE 1024
7 int main()
8 {
9 int fd;
10 int ret;
11 struct aiocb test_aio;
12 if((fd=open("test.txt",O_RDONLY))==-1)printf("open wrong");
13 memset(&test_aio,0,sizeof(struct aiocb));
14 test_aio.aio_buf=malloc(sizeof(char)*BUFFSIZE);
15 test_aio.aio_fildes=fd;
16 test_aio.aio_nbytes=BUFFSIZE;
17 test_aio.aio_offset=0;
18 if((ret=aio_read(&test_aio))<0)
19 printf("wrong aio_read");
20 //这种是一直在等待中 让其一直在忙等待中
21 while(aio_error(&test_aio)==EINPROGRESS);
22 if((ret=aio_return(&test_aio))>0)
23 {
24
25 printf("异步读取数据已经成功!\n");
26 printf("%s",test_aio.aio_buf);
27 }
28 else
29 printf("异步读取数据失败!");
30
31 }
可以看到这个其实是一个很简单的数据读取到内存中来。我们用strace -f ./a.out 做一个查询,看下系统在接受这个可执行程序之后都做了什么动作:
toms@toms-Vostro-260s:~/C_C++_TEST$ strace -f ./a.out
execve("./a.out", ["./a.out"], [/* 47 vars */]) = 0
brk(0) = 0x9e3e000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb779b000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=100835, ...}) = 0
mmap2(NULL, 100835, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7782000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3 -------------------------------------- (1)
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\31\0\0004\0\0\0"..., 512) = 512-----------------(2)
fstat64(3, {st_mode=S_IFREG|0644, st_size=30696, ...}) = 0
mmap2(NULL, 33352, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7779000
mmap2(0xb7780000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6) = 0xb7780000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\232\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1770984, ...}) = 0
mmap2(NULL, 1780508, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75c6000
mmap2(0xb7773000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ad) = 0xb7773000
mmap2(0xb7776000, 11036, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7776000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320[\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=124637, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75c5000
mmap2(NULL, 107008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75aa000
mmap2(0xb75c1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16) = 0xb75c1000
mmap2(0xb75c3000, 4608, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb75c3000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75a9000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75a96c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7773000, 8192, PROT_READ) = 0
mprotect(0xb75c1000, 4096, PROT_READ) = 0
mprotect(0xb7780000, 4096, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb77be000, 4096, PROT_READ) = 0
munmap(0xb7782000, 100835) = 0
set_tid_address(0xb75a9728) = 3811
set_robust_list(0xb75a9730, 0xc) = 0
futex(0xbfaf3604, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, b75a96c0) = -1 EAGAIN (Resource temporarily unavailable)
rt_sigaction(SIGRTMIN, {0xb75af5f0, [], SA_SIGINFO}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0xb75af680, [], SA_RESTART|SA_SIGINFO}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
uname({sys="Linux", node="toms-Vostro-260s", ...}) = 0
open("test.txt", O_RDONLY) = 3
brk(0) = 0x9e3e000
brk(0x9e5f000) = 0x9e5f000
sched_getparam(3811, { 0 }) = 0
sched_getscheduler(3811) = 0 (SCHED_OTHER)
rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], [], 8) = 0
mmap2(NULL, 27520, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xb7794000
mprotect(0xb7794000, 4096, PROT_NONE) = 0
clone(Process 3812 attached-----------------------------------------------------------------------------------------(3)
child_stack=0xb7799fe4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb779a728, {entry_number:6, base_addr:0xb779a6c0, limit:1048575, seg_32bit:1, contents:0,
read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb779a728) = 3812
[pid 3811] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid 3812] set_robust_list(0xb779a730, 0xc) = 0
[pid 3812] pread64(3, "hello \347\254\254\344\270\200\344\270\252linux aio\347\250\213\345\272\217\357\274"..., 1024, 0) = 34 -------------------------------------------------------------------------------------(4)
[pid 3812] getuid32( <unfinished ...>
[pid 3811] fstat64(1, <u
ac93
nfinished ...>
[pid 3812] <... getuid32 resumed> ) = 1000
[pid 3811] <... fstat64 resumed> {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
[pid 3812] rt_sigqueueinfo(3811, SIG_0, {} <unfinished ...>
[pid 3811] mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
[pid 3812] <... rt_sigqueueinfo resumed> ) = 0
[pid 3811] <... mmap2 resumed> ) = 0xb7793000
[pid 3812] gettimeofday( <unfinished ...>
[pid 3811] write(1, "\345\274\202\346\255\245\350\257\273\345\217\226\346\225\260\346\215\256\345\267\262\347\273\217\346\210\220\345\212\237\357\274"..., 34异步读取数据已经成功!
<unfinished ...>
[pid 3812] <... gettimeofday resumed> {1383114881, 327461}, NULL) = 0
[pid 3811] <... write resumed> ) = 34
[pid 3812] clock_gettime(CLOCK_REALTIME, <unfinished ...>
[pid 3811] write(1, "hello \347\254\254\344\270\200\344\270\252linux aio\347\250\213\345\272\217\357\274"..., 34hello 第一个linux aio程序!
<unfinished ...>
[pid 3812] <... clock_gettime resumed> {1383114881, 327594745}) = 0
[pid 3811] <... write resumed> ) = 34
[pid 3812] futex(0xb77811a4, FUTEX_WAIT_PRIVATE, 1, {0, 999866255} <unfinished ...>
[pid 3811] exit_group(34) = ?
这是一个完整的过程哦 ,可能东西比较多 一步步的来看下:
首先可以看出来 这个pid 有2个进程号 pid 3812 和3811 不往深入分析 本身他就调用了linux本身的创建进程,看过LINUX内核的人应该知道:这里的 (3)调用的是clone. 这个动作就是由aio_read()函数触发的!!
Linux的轻量级进程---就是线程。也就是其本身而言,就是调用Clone一个进程来执行读文件操作,自身进程继续执行,我们在来看上面的调用 ;3182是子进程 3181是父进程。为什么要分析这个呢 ?这个其实对后面的分析aio_read到底做了什么动作是非常重要的。
对于3182而言 :我们执行了(4)也就是我们本身而言,子进程就是异步的一个模拟,同步模拟异步。pread()这个函数是一个阻塞函数哦,pread()本身而言,可能会导致3182的一个阻塞,阻塞完成了I/O 必须通过信号量机制传递。这个信号量在后面有提示的。后面的过程我觉得就比较简单了
也就是说 AIO本身而言 是自己创建线程 用同步来模拟异步哦 表示这样的思路可以用pthread库写一个来模拟异步的传输,下一篇我们就把上面那个代码用pthread线程机制来模拟的代码传上来。
当然本身而言 AIO应该在很多方面做了优化 我仅仅是分析出这个AIO的一个大体的执行流程,然后对以后的分析性能是有帮助的!!
相关文章推荐
- Crack Searching AIO (by avg) 下载
- Ajax异步(请求)提交类 支持跨域
- javascript 异步的innerHTML使用分析
- Android 异步加载图片的实例代码
- Android中BroadcastReceiver(异步接收广播Intent)的使用
- 使用异步方式调用同步方法(实例详解)
- ASP.NET之自定义异步HTTP处理程序(图文教程)
- 基于TCP异步Socket模型的介绍
- Ajax异步提交表单数据的说明及方法实例
- jQuery异步上传文件插件ajaxFileUpload详细介绍
- JavaScript异步编程:异步数据收集的具体方法
- Javascript 异步加载详解
- java 同步 异步
- jquery中post,get,ajax请求相关
- I/O模型以及select和poll函数
- Alertable I/O
- JavaScript XMLHttpRequest
- MY-I.MX6Q双屏异步播放高清视频
- AIX系统下AIO(Asynchronous I/O)
- Android完美解决GridView异步加载图片和加载大量图片时出现Out Of Memory问题