4-3 Неблокирующая IO

Неблокирования ввод-вывод (неблокирующий IO)

Linux сокет может быть выполнен так, чтобы она становится неблокирующей. Когда неблокирующий разъем для операции считывания, процесс, как это:

Неблокируемая

Как видно из рисунка, когда пользовательский процесс выдает операцию чтения, если ядро ​​данных не готово, то он не блокирует пользовательский процесс, но сразу же возвращает ошибку. С точки зрения пользовательского процесса, он инициирует операцию чтения после того, как мы не должны ждать, но тут же получил результат. Пользовательский процесс является результатом ошибки суждения, он знает, что данные не были готовы, так что пользователь может инициировать запросы делать другие вещи, в течение интервала времени для чтения, или направляется непосредственно читать эту операцию еще раз в следующем. После того, как данные будут готовы к ядру, и снова получил пользовательский процесс системного вызова, то он будет немедленно копировать данные в памяти пользователя (этот этап все еще заблокированы), а затем вернуться.

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

Поэтому, не блокируя IO, пользовательский процесс на самом деле нужно постоянно спрашивать о данных ядра готовы или нет.

Примеры неблокирующего 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'))

Тем не менее, не блокирующая модель IO не рекомендуется.

Мы не можем иначе преимущества: возможность делать другими живут (в том числе представления других задач, то есть, «фон» может иметь несколько задач, «» а «» исполнение) ждет времени выполнения задачи.

Но и скрывать свои недостатки:

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

Кроме того, в этом варианте осуществления RECV () функции больше смысла «завершение работы„роль, фактическая операционная система обеспечивает более эффективное обнаружение“операция закончена,«что интерфейсы, например, выбрать () мультиплексированных режим использования, можно обнаружить множество соединений является активным.

рекомендация

отwww.cnblogs.com/shibojie/p/11664827.html
4-3