- 浏览: 409599 次
最新评论
-
iunknown:
909601686 写道我理解下来,之所以使用奇数应该不仅仅是 ...
以两军问题为背景来演绎Basic Paxos -
909601686:
我理解下来,之所以使用奇数应该不仅仅是为了判断谁赢。而是这样就 ...
以两军问题为背景来演绎Basic Paxos -
feclipse:
you are my hero! 看了你的图示之后,我的理解 ...
以两军问题为背景来演绎Basic Paxos -
lcc0739:
相当好!通俗易懂,看了好几篇paxos只有你这个最深入浅出!
以两军问题为背景来演绎Basic Paxos -
iunknown:
tangfu 写道hi,问一下,博主提供的库与pb兼容么,比如 ...
一个轻量的 wire format 解释器(google protobuf 的二进制格式)
集成 IOCP 到 Libevent
完整的代码在
http://spserver.googlecode.com/files/libevent-1.4.4-iocp-3.zip
2008.08.23
http://spserver.googlecode.com/files/libevent-1.4.5-stable-iocp-2.zip
增加了 non-blocking connect 的支持。
IOCP 是真正的异步 IO ,Libevent 提供的是一个 event-driven 的接口。
异步 IO 和 event-driven 的区别:
1.对于 event-driven,需要等待内核通知我们去启动一个IO操作,然后直接得到IO操作的结果
2.对于异步IO,我们可以随时无阻塞地启动 IO,然后由内核通知我们 IO 操作何时完成
要把 IOCP 集成到 libevent ,基本的思路是用 IOCP 模拟 event-driven 接口。
在 IOCP 中有一个特性,刚好可以用来模拟 event-driven 的接口:zero byte buffer recv/send。
当我们发起 WSARecv,WSASend 的时候,需要用 WSABUF 传递一个 buffer 进去。
如果我们把这个 buffer 设置为 zero byte ,那么当 socket 可读,或者可写的时候,
通过 GQCS 同样可以得到结果。这样就等于是模拟了 event-driven 的接口。
另一方面,Windows 的 WSAEventSelect 函数提供了一个 event-driven 的 accept 功能。
问题在于如何把 IOCP 和 WSAEventSelect 集成起来。
通过查看 WSARecv,WSASend 的接口,可以注意到这两个接口都需要提供一个 OVERLAPPED 的结构体。
在这个结构体里有一个 hEvent 的成员。如果设置了这个 hEvent 参数,那么当这个 IO 请求完成的时候,
hEvent 将会被 signal 。详细信息可以参考下面这个 URL :
http://msdn.microsoft.com/en-us/library/ms742203(VS.85).aspx
这样看起来可以通过 WSAWaitForMultipleEvents 来集成 IOCP 和 WSAEventSelect 。
1.用 WSAEventSelect 来处理 accept event
2.用 IOCP 来处理 recv/send event ,发起 recv/send 请求的时候,设置 OVERLAPPED 的 hEvent 参数
3.把 WSAEventSelect 的 hEvent 和 IOCP 的 hEvent 收集起来,用 WSAWaitForMultipleEvents 统一处理
需要注意的时候,上述的第二步中,不需要为每个 recv/send 请求生成一个新的 hEvent,
而是所有的 recv/send 共用一个 hEvent 就行了。
在下面这个 URL 中提到,对于一个 hEvent 如果已经是 signal ,再次 signal ,不会有副作用。
http://msdn.microsoft.com/en-us/library/ms686211(VS.85).aspx
用代码来描述上面的这个思路,大概是下面这样。
首先创建 64 个 hEvent ,其中的 objects[0] 就用于 IOCP 中所有的 IO 操作。
其他剩余的 63 个 hEvent ,就可以用于 accept event 。
程序首先调用 WSAWaitForMultipleEvents 来等待 event 发生。
如果发现是 objects[0] 有事件,那么是 IOCP 的 IO 操作已经有完成的,就调用 GQCS 来处理。
如果发现是其他的 objects 有事件,那么就是有 accept event 发生。
GetQueuedCompletionStatusEx 和 GetQueuedCompletionStatus 的差别是前者可以一次得到多个 event 。
GetQueuedCompletionStatus 本身也支持超时的。
这里提到的要用 WSAWaitForMultipleEvents ,主要是解决 IOCP 和 WSAEventSelect 的集成。
在使用 libevent 的场景中,通常都需要把 accept,recv,send 这几个事件在同一个 event_base 里面来跑,因此集成 IOCP 和 WSAEventSelect 是很有必要的。如果不需要集成 accept 事件,那么只需要使用 zero byte buffer 就可以把 IOCP 当作 select 来用了。
这两天对 libevent 1.4.4 里面的单元测试案例进行了测试,发现了一个问题
http://msdn.microsoft.com/en-us/library/ms686358(VS.85).aspx
当多个 WSARecv/WSASend 使用同一个 Event 的时候,会产生 race condition 。
后来在 WSAWaitForMultipleEvents 之前,先调用一次 GetQueuedCompletionStatus ,这样可以消除这个 race condition 的影响。目前已经可以通过 regress.c 中大部分测试案例了。少部分失败的案例主要是由于环境的问题,现在是用 vc6 作为开发环境的,libevent 1.4.4 中的部分代码需要更高版本的 vs 。
最新的代码:http://spserver.googlecode.com/files/libevent-1.4.4-iocp-2.zip
对于 epoll 和 iocp 都算不上熟悉,只是根据自己的兴趣去找了一下资料来看,然后写了一些代码来验证一下自己的理解。就目前的测试来看,两者在高并发和 IO 性能方面,都是不错的。但依目前的经验,很难说已经测试到了它们各自的最优情况。对于这种高并发的性能测试,对于系统参数的调整也是一个很大的方面。如果要做具体的比较,那么需要列举具体的应用场景,具体把代码实现出来,才能做一个比较客观的对比。
Linux 没有异步 IO 应该说的是没有针对 socket 的异步 IO 吧?对于文件 IO 是有 AIO 这套接口的。
iocp 之 socket 版本?这个描述有点不解。
不过通常都是认为 linux 的 epoll 是和 windows 的 iocp 相对应的一种技术。两者常常会被相提并论,主要应该是两者都对高并发提供了良好的支持。但是从细节的角度来说,两者在 IO 模型上是不同的。epoll api 本身就只支持一种 event-driven 的模型,iocp api 除了 async IO 模型之外,如果使用 zero byte buffer 还可以支持 event-driven 的模型。
原来你就是讨论组内的那位stephen.nil阿
呵呵,真不错
对于 epoll 和 iocp 都算不上熟悉,只是根据自己的兴趣去找了一下资料来看,然后写了一些代码来验证一下自己的理解。就目前的测试来看,两者在高并发和 IO 性能方面,都是不错的。但依目前的经验,很难说已经测试到了它们各自的最优情况。对于这种高并发的性能测试,对于系统参数的调整也是一个很大的方面。如果要做具体的比较,那么需要列举具体的应用场景,具体把代码实现出来,才能做一个比较客观的对比。
Linux 没有异步 IO 应该说的是没有针对 socket 的异步 IO 吧?对于文件 IO 是有 AIO 这套接口的。
iocp 之 socket 版本?这个描述有点不解。
不过通常都是认为 linux 的 epoll 是和 windows 的 iocp 相对应的一种技术。两者常常会被相提并论,主要应该是两者都对高并发提供了良好的支持。但是从细节的角度来说,两者在 IO 模型上是不同的。epoll api 本身就只支持一种 event-driven 的模型,iocp api 除了 async IO 模型之外,如果使用 zero byte buffer 还可以支持 event-driven 的模型。
完整的代码在
http://spserver.googlecode.com/files/libevent-1.4.4-iocp-3.zip
2008.08.23
http://spserver.googlecode.com/files/libevent-1.4.5-stable-iocp-2.zip
增加了 non-blocking connect 的支持。
IOCP 是真正的异步 IO ,Libevent 提供的是一个 event-driven 的接口。
异步 IO 和 event-driven 的区别:
1.对于 event-driven,需要等待内核通知我们去启动一个IO操作,然后直接得到IO操作的结果
2.对于异步IO,我们可以随时无阻塞地启动 IO,然后由内核通知我们 IO 操作何时完成
要把 IOCP 集成到 libevent ,基本的思路是用 IOCP 模拟 event-driven 接口。
在 IOCP 中有一个特性,刚好可以用来模拟 event-driven 的接口:zero byte buffer recv/send。
当我们发起 WSARecv,WSASend 的时候,需要用 WSABUF 传递一个 buffer 进去。
如果我们把这个 buffer 设置为 zero byte ,那么当 socket 可读,或者可写的时候,
通过 GQCS 同样可以得到结果。这样就等于是模拟了 event-driven 的接口。
另一方面,Windows 的 WSAEventSelect 函数提供了一个 event-driven 的 accept 功能。
... WSAEventSelect( listenFd, hEvent, FD_ACCEPT ); ...
问题在于如何把 IOCP 和 WSAEventSelect 集成起来。
通过查看 WSARecv,WSASend 的接口,可以注意到这两个接口都需要提供一个 OVERLAPPED 的结构体。
在这个结构体里有一个 hEvent 的成员。如果设置了这个 hEvent 参数,那么当这个 IO 请求完成的时候,
hEvent 将会被 signal 。详细信息可以参考下面这个 URL :
http://msdn.microsoft.com/en-us/library/ms742203(VS.85).aspx
引用
If the lpCompletionRoutine parameter is NULL, the hEvent parameter of lpOverlapped is signaled when the overlapped operation completes if it contains a valid event object handle. An application can use WSAWaitForMultipleEvents or WSAGetOverlappedResult to wait or poll on the event object.
这样看起来可以通过 WSAWaitForMultipleEvents 来集成 IOCP 和 WSAEventSelect 。
1.用 WSAEventSelect 来处理 accept event
2.用 IOCP 来处理 recv/send event ,发起 recv/send 请求的时候,设置 OVERLAPPED 的 hEvent 参数
3.把 WSAEventSelect 的 hEvent 和 IOCP 的 hEvent 收集起来,用 WSAWaitForMultipleEvents 统一处理
需要注意的时候,上述的第二步中,不需要为每个 recv/send 请求生成一个新的 hEvent,
而是所有的 recv/send 共用一个 hEvent 就行了。
在下面这个 URL 中提到,对于一个 hEvent 如果已经是 signal ,再次 signal ,不会有副作用。
http://msdn.microsoft.com/en-us/library/ms686211(VS.85).aspx
引用
Setting an event that is already set has no effect.
用代码来描述上面的这个思路,大概是下面这样。
首先创建 64 个 hEvent ,其中的 objects[0] 就用于 IOCP 中所有的 IO 操作。
其他剩余的 63 个 hEvent ,就可以用于 accept event 。
程序首先调用 WSAWaitForMultipleEvents 来等待 event 发生。
如果发现是 objects[0] 有事件,那么是 IOCP 的 IO 操作已经有完成的,就调用 GQCS 来处理。
如果发现是其他的 objects 有事件,那么就是有 accept event 发生。
/* objects[0] for iocp operations, object[1..63] for accept */ HANDLE objects[64]; struct event * accepts[64]; struct win32iocp_event event1; event1.overlapped.hEvent = objects[0]; WSARecv( ..., &event1.overlapped, ... ); .... struct win32iocp_event event2; event2.overlapped.hEvent = objects[0]; WSASend( ..., &event2.overlapped, ... ); ... WSAEventSelect( ev1->ev_fd, objects[1], FD_ACCEPT ); accepts[1] = ev1; ... WSAEventSelect( ev2->ev_fd, objects[2], FD_ACCEPT ); accepts[2] = ev2; ... int index = WSAWaitForMultipleEvents( 64, objects, FALSE, timeout, FALSE ); index = index - WSA_WAIT_EVENT_0; if( index > 0 ) { struct event * event = win32iocp_op->accepts[index]; event_active (event, EV_READ | EV_ACCEPT, 1); } if( index == 0 ) { for( ; ; ) { GetQueuedCompletionPort( ...... ); } }
评论
9 楼
iunknown
2008-08-23
http://spserver.googlecode.com/files/libevent-1.4.5-stable-iocp-2.zip
最新的版本使用类似于解决 non-blocking accept 的方法实现了 non-blocking connect。
需要增加一个 EV_CONNECT 的标志位,增加了一个 conn_test 的例子来示范如何使用。
最新的版本使用类似于解决 non-blocking accept 的方法实现了 non-blocking connect。
需要增加一个 EV_CONNECT 的标志位,增加了一个 conn_test 的例子来示范如何使用。
8 楼
iunknown
2008-06-05
去找了 memcached for win32 的源代码,结果可以顺利编译,并且运行起来也很正常。
http://jehiah.cz/projects/memcached-win32/
修改后的,libevent + iocp + memcached 代码下载
http://spserver.googlecode.com/files/memcached-1.2.1-iocp.zip
http://spserver.googlecode.com/files/libevent-1.4.4-iocp-2.zip
http://jehiah.cz/projects/memcached-win32/
修改后的,libevent + iocp + memcached 代码下载
http://spserver.googlecode.com/files/memcached-1.2.1-iocp.zip
http://spserver.googlecode.com/files/libevent-1.4.4-iocp-2.zip
7 楼
iunknown
2008-06-05
qiezi 写道
GetQueuedCompletionStatusEx也支持超时,用它代替select也可以吧?试试移植一个iocp版本?
GetQueuedCompletionStatusEx 和 GetQueuedCompletionStatus 的差别是前者可以一次得到多个 event 。
GetQueuedCompletionStatus 本身也支持超时的。
这里提到的要用 WSAWaitForMultipleEvents ,主要是解决 IOCP 和 WSAEventSelect 的集成。
在使用 libevent 的场景中,通常都需要把 accept,recv,send 这几个事件在同一个 event_base 里面来跑,因此集成 IOCP 和 WSAEventSelect 是很有必要的。如果不需要集成 accept 事件,那么只需要使用 zero byte buffer 就可以把 IOCP 当作 select 来用了。
这两天对 libevent 1.4.4 里面的单元测试案例进行了测试,发现了一个问题
http://msdn.microsoft.com/en-us/library/ms686358(VS.85).aspx
引用
Synchronization and Overlapped Input and Output
If an event is used, the hEvent member of the OVERLAPPED structure specifies a
handle to the allocated event object. The system sets the state of the event object
to nonsignaled when a call to the I/O function returns before the operation has been completed.
If an event is used, the hEvent member of the OVERLAPPED structure specifies a
handle to the allocated event object. The system sets the state of the event object
to nonsignaled when a call to the I/O function returns before the operation has been completed.
当多个 WSARecv/WSASend 使用同一个 Event 的时候,会产生 race condition 。
后来在 WSAWaitForMultipleEvents 之前,先调用一次 GetQueuedCompletionStatus ,这样可以消除这个 race condition 的影响。目前已经可以通过 regress.c 中大部分测试案例了。少部分失败的案例主要是由于环境的问题,现在是用 vc6 作为开发环境的,libevent 1.4.4 中的部分代码需要更高版本的 vs 。
最新的代码:http://spserver.googlecode.com/files/libevent-1.4.4-iocp-2.zip
6 楼
qiezi
2008-06-05
GetQueuedCompletionStatusEx也支持超时,用它代替select也可以吧?试试移植一个iocp版本?
5 楼
qiezi
2008-06-05
linux/solaris上的aio有多种回调/通知方式,可能和libevent结合的最简单方式是signal,因为libevent也支持它,不过我没试过,在linux下用过的是内核线程直接写同步队列然后发送socket通知唤醒libevent去处理。solaris上可以用一个port专门处理aio通知,非常方便。虽然aio大部分时候用于处理文件IO,不过它和iocp应该有相似之处吧?iocp的细节我不清楚,如果是“完成-通知”或“完成-回调”方式,应该都可以和libevent结合。
4 楼
wow
2008-06-04
SPServer是一个很不错的框架,受到启发,我用boost::asio实现了一个类似的框架,其中的一个特点,就是很容易在单线程和多线程之间切换,好像在您以前的文章中讨论过这个问题,
原理就是实现一个Wrap类,自动实现线程的传递
http://www.cppblog.com/eXile/archive/2008/06/04/51430.html#52178
原理就是实现一个Wrap类,自动实现线程的传递
http://www.cppblog.com/eXile/archive/2008/06/04/51430.html#52178
3 楼
关中刀客
2008-06-03
iunknown 写道
bigpanda 写道
近来 iunknown 写了很多用 iocp 的东东。请教一下能否比较一下 Linux 的 epoll 和 windows 的 iocp?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下?
对于 epoll 和 iocp 都算不上熟悉,只是根据自己的兴趣去找了一下资料来看,然后写了一些代码来验证一下自己的理解。就目前的测试来看,两者在高并发和 IO 性能方面,都是不错的。但依目前的经验,很难说已经测试到了它们各自的最优情况。对于这种高并发的性能测试,对于系统参数的调整也是一个很大的方面。如果要做具体的比较,那么需要列举具体的应用场景,具体把代码实现出来,才能做一个比较客观的对比。
Linux 没有异步 IO 应该说的是没有针对 socket 的异步 IO 吧?对于文件 IO 是有 AIO 这套接口的。
iocp 之 socket 版本?这个描述有点不解。
不过通常都是认为 linux 的 epoll 是和 windows 的 iocp 相对应的一种技术。两者常常会被相提并论,主要应该是两者都对高并发提供了良好的支持。但是从细节的角度来说,两者在 IO 模型上是不同的。epoll api 本身就只支持一种 event-driven 的模型,iocp api 除了 async IO 模型之外,如果使用 zero byte buffer 还可以支持 event-driven 的模型。
原来你就是讨论组内的那位stephen.nil阿
呵呵,真不错
2 楼
iunknown
2008-06-03
bigpanda 写道
近来 iunknown 写了很多用 iocp 的东东。请教一下能否比较一下 Linux 的 epoll 和 windows 的 iocp?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下?
对于 epoll 和 iocp 都算不上熟悉,只是根据自己的兴趣去找了一下资料来看,然后写了一些代码来验证一下自己的理解。就目前的测试来看,两者在高并发和 IO 性能方面,都是不错的。但依目前的经验,很难说已经测试到了它们各自的最优情况。对于这种高并发的性能测试,对于系统参数的调整也是一个很大的方面。如果要做具体的比较,那么需要列举具体的应用场景,具体把代码实现出来,才能做一个比较客观的对比。
Linux 没有异步 IO 应该说的是没有针对 socket 的异步 IO 吧?对于文件 IO 是有 AIO 这套接口的。
iocp 之 socket 版本?这个描述有点不解。
不过通常都是认为 linux 的 epoll 是和 windows 的 iocp 相对应的一种技术。两者常常会被相提并论,主要应该是两者都对高并发提供了良好的支持。但是从细节的角度来说,两者在 IO 模型上是不同的。epoll api 本身就只支持一种 event-driven 的模型,iocp api 除了 async IO 模型之外,如果使用 zero byte buffer 还可以支持 event-driven 的模型。
1 楼
bigpanda
2008-06-03
近来 iunknown 写了很多用 iocp 的东东。请教一下能否比较一下 Linux 的 epoll 和 windows 的 iocp?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下?
发表评论
-
以两军问题为背景来演绎Basic Paxos
2015-09-28 10:28 19186背景 在计算机通信理 ... -
自动化解决编译依赖问题
2010-12-04 14:02 3732一个用 c++ 实现的系统,过于庞大,依赖很复杂,还要变化很频 ... -
调试堆栈错乱的问题
2010-07-15 00:57 2585如果没有简单的重现办法,或者只是偶尔出现的话,可以通过 gli ... -
让设置 suid 的程序也产生 coredump
2010-05-11 11:24 2644被 suid 的程序要产生 coredump 文件,还需要额外 ... -
[zz]What does anon mean for pmap?
2010-02-26 21:12 4928http://stackoverflow.com/questi ... -
[zz]Troubleshooting Memory Usage
2010-01-13 21:05 1243http://rimuhosting.com/howto/me ... -
Half-Sync/Half-Async 和 Leader/Follower 模式的实现代码
2009-12-27 13:33 3181把之前发表过的一篇文 ... -
vc6 设置 pre-build 步骤
2009-11-06 22:52 1487把 spdatapickle 移植到 win32 平台,使用 ... -
socat
2009-10-28 23:11 1353socat 类似 telnet ,但是支持多种协议。 比如要 ... -
一个用于快速定位 C/C++ 函数返回位置的 macro
2009-09-28 23:11 1902这个 macro 是这样的 #define return ... -
使用 gettimeofday 来测量执行时间存在的问题
2009-08-01 17:25 5336之前一直使用 cprof 来分 ... -
[zz]Tokyo Cabinet Table Engine
2009-07-05 22:26 1388Sounds impressive and cool. I w ... -
[zz]Tokyo Cabinet Observations
2009-05-05 17:41 1407http://parand.com/say/index.php ... -
[zz]Save SQLite memory database to file
2009-04-25 15:45 3144http://itsystementwicklung.de/p ... -
SpamAssassin, spf, greylist, dnsbl 相关的 milter 编译安装
2009-04-05 14:15 1636首先,如果系统中没有 libmilter.a 库,那么下载 s ... -
milter client 的实现
2009-03-28 19:38 1213在浏览了 milter 的协议描述和具体的实现之后,决定自己动 ... -
[zz]break when opening certain file
2009-02-16 17:38 1155http://www.nabble.com/break-whe ... -
linux inotify 通知信息不包括 user 和 process 的原因
2008-10-09 16:59 1417http://groups.google.com/group/ ... -
在 SPServer 中集成 IOCP 和 SSL
2008-06-20 22:27 3392打算把 Windows 的 SSPI 集成到 SPServer ... -
Reasons for threading
2008-06-11 20:49 1232http://www.sagemath.org:9001/Gl ...
相关推荐
集成IOCP到libevent是一个复杂的任务,需要深入理解两个技术的内部工作原理。完成后,它将使基于libevent的应用在Windows平台上实现更高效的异步I/O处理,尤其对于高并发服务器,性能提升可能非常显著。文件...
(3)切换到libevent-2.0.11-stable目录 (4)执行nmake /f Makefile.nmake 2.直接使用我已经建立好在VS2008下的编译工程,如果不熟悉上面的nmake编译方法, 直接编译libevent-2.0.11工程即可生成这个三个库文件。...
1. 在libevent 1.4版之前,只有一个名为`libevent`的库,它包含了当前分散到`libevent_core`和`libevent_extra`中的所有功能。 2. 在2.0版之前,libevent并不支持锁机制,这意味着如果在多线程环境中使用同一结构体...
- **编译前准备**: 下载libevent源码,并解压到本地目录。 - **编译步骤**: 使用CMake进行配置,并通过Visual Studio生成解决方案文件。最后,使用VS2017打开解决方案并编译。 **1.2 使用VS2017编译zlib源码** - *...
由于Coturn依赖于libevent库来处理网络事件,因此libevent的性能直接影响到Coturn服务器的响应速度和处理能力。 libevent的主要特点包括: 1. **多事件机制**:libevent支持多种操作系统提供的事件通知机制,如...
本示例“DameoLibeventServer”正是基于libevent库在Windows 10操作系统和Visual Studio 2019集成开发环境中实现的一个TCP服务端程序。 libevent库的核心功能在于它能够管理大量的异步事件,并且以非阻塞的方式处理...
5. **数据库集成**:游戏数据通常存储在数据库中,框架可能集成了常见的数据库接口,如MySQL、PostgreSQL或MongoDB,以便于进行数据读写操作。 6. **状态机设计**:游戏服务器可能使用状态机模式处理不同游戏阶段,...
6. **事件驱动编程**:如使用libevent或libev等库,可以更高效地处理大量并发连接,当有事件发生时(如新连接、数据到达等),事件驱动框架会通知应用程序进行相应的处理。 7. **错误处理**:在实际开发中,必须...
除了基础的Winsock API,还有许多现成的网络编程框架可供选择,如ACE、Poco、libevent等,它们提供了更高级别的抽象,简化了网络编程的复杂性。 通过以上知识点,开发者可以使用Visual C++创建复杂的网络应用程序,...
4. **异步I/O**:为了进一步提高效率,可以使用异步I/O模型,如Linux的epoll或Windows的IOCP,它们允许程序在等待I/O操作完成时执行其他任务。 5. **事件驱动编程**:另一种处理并发的方式是使用事件驱动编程,如...