4-3 Non-blocking IO

Nonblocking IO (non-blocking IO)

Linux, the socket can be provided so that it becomes non-blocking. When a non-blocking socket for a read operation, the process is like this:

Non-blocking

As it can be seen from the figure, when a user process issues a read operation, if the data kernel is not ready, then it does not block the user process, but immediately returns an error. From the perspective of the user process, it initiates a read operation after, we do not need to wait, but immediately got a result. User process is the result of a judgment error, it knows that the data was not ready, so the user can then initiate inquiries do other things within the read time interval, or sent directly read this operation again in the next. Once the data is ready for kernel, and again received a system call user process, then it will immediately copy the data to the user memory (this stage is still blocked), and then return.

也就是说非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,
此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。重复上面的过程,
循环往复的进行recvform系统调用。这个过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,
进行数据处理。需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态。

Therefore, non-blocking IO, the user process is actually a need to constantly ask about kernel data ready or not.

Examples of non-blocking IO

#服务端
from socket import *

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8099))
server.listen(5)
server.setblocking(False)


rlist=[]
wlist=[]
while True:
    try:
        conn, addr = server.accept()
        rlist.append(conn)
        print(rlist)

    except BlockingIOError:
        del_rlist=[]
        for sock in rlist:
            try:
                data=sock.recv(1024)
                if not data:
                    del_rlist.append(sock)
                wlist.append((sock,data.upper()))
            except BlockingIOError:
                continue
            except Exception:
                sock.close()
                del_rlist.append(sock)

        del_wlist=[]
        for item in wlist:
            try:
                sock = item[0]
                data = item[1]
                sock.send(data)
                del_wlist.append(item)
            except BlockingIOError:
                pass

        for item in del_wlist:
            wlist.remove(item)


        for sock in del_rlist:
            rlist.remove(sock)

server.close()


#客户端
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8080))

while True:
    msg=input('>>: ')
    if not msg:continue
    c.send(msg.encode('utf-8'))
    data=c.recv(1024)
    print(data.decode('utf-8'))

However, non-blocking IO model is not recommended.

We can not otherwise advantages: the ability to do other live (including the submission of other tasks, that is, the "background" can have multiple tasks, "" while "" execution) waiting for task completion time.

But also conceal its shortcomings:

1. 循环调用recv()将大幅度推高CPU占用率;这也是我们在代码中留一句time.sleep(2)的原因,否则在低配主机下极容易出现卡机情况
2. 任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。
这会导致整体数据吞吐量的降低。

Further, in this embodiment recv () functions is more sense 'operation completion "role, the actual operating system provides a more efficient detection" operation is finished, "that interfaces, e.g. select () multiplexed use mode, can detect a plurality of connections is active.

Guess you like

Origin www.cnblogs.com/shibojie/p/11664827.html