本文解释高性能网络编程中的几个基本概念。
阻塞(blocking)和非阻塞(non-blocking):阻塞和非阻塞是指用户进程在做read(), write()等系统调用的时候,根据系统调用当前所处的状态而采取的不同的处理策略。拿read()函数来说,阻塞情况下,如果没有数据到达,则用户进程一直等待(睡眠),直到数据到达,这个过程中用户进程处于睡眠状态,干不了其他事情;非阻塞情况下,如果数据没有到达,则立即返回给用户进程一个状态信息(EAGAIN,EWOULDBLOCK等),用户进程根据这个状态信息选择继续调用read()还是去干其他事情。
同步(synchronous)和异步(asynchronous):同步和异步是整个IO操作中用户进程的参与程度。还是拿read()来说,同步的情况下,用户进程会全程参与到read()系统调用中,不管是以阻塞的方式还是非阻塞的方式,用户进程跟内核不断地交互,直到所有的数据都收到;而在异步的情况下,用户进程只需要告知内核我要做read()操作,你给我把该网络fd上到来的数据都存到buf中,存好了告诉我,然后用户进程就去做其他事情了,当内核把所有的数据都存到buf中时,再通知用户进程,用户进程再做相应的处理。可以看出,比起同步IO,异步IO充分解放了用户进程,使得它在相同的时间内干更多的活。
系统IO可以分为: blocking IO, or non-blocking synchronous IO, 和non-blocking asynchronous IO三种
关于它们三者的区别,我想下面的三段话解释得够非常好:
Blocking I/O means that the calling system does not return control to the caller until the operation is finished. As a result, the caller is blocked and cannot perform other activities during that time. Most important, the caller thread cannot be reused for other request processing while waiting for the I/O to complete, and becomes a wasted resource during that time. For example, a read()
operation on a socket in blocking mode will not return control if the socket buffer is empty until some data becomes available.
a non-blocking synchronous call returns control to the caller immediately. The caller is not made to wait, and the invoked system immediately returns one of two responses: If the call was executed and the results are ready, then the caller is told of that. Alternatively, the invoked system can tell the caller that the system has no resources (no data in the socket) to perform the requested action. In that case, it is the responsibility of the caller may repeat the call until it succeeds. For example, a read()
operation on a socket in non-blocking mode may return the number of read bytes or a special return code -1 with errno set to EWOULBLOCK/EAGAIN
, meaning "not ready; try again later."
In a non-blocking asynchronous call, the calling function returns control to the caller immediately, reporting that the requested action was started. The calling system will execute the caller's request using additional system resources/threads and will notify the caller (by callback for example), when the result is ready for processing. For example, a Windows ReadFile()
or POSIX aio_read()
API returns immediately and initiates an internal system read operation. Of the three approaches, this non-blocking asynchronous approach offers the best scalability and performance.