python 并发编程:阻塞 IO

tech2022-10-22  130

IO 的模型:

了解概念:

阻塞 I/O:应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当 前线程,自然就不能执行其他任务

非阻塞 I/O:应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执 行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果

同步 I/O:应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获 得 I/O 响应

异步 I/O:应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是 继续执行就可以

阻塞 IO(blocking IO)

在 Linux 中,默认情况下所有的 socket 都是 blocking,一个典型的读操作流程大概是这样:

552 x 331

当用户进程调用了 recvfrom 这个系统调用,kernel 就开始了 IO 的第一个阶段:准备数据。对于 network io 来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的 udp 包),这个时候 kernel 就要等待足够的数据到来

而在用户进程这边,整个进程会被阻塞,当 kernel 一直等到数据准备好了,它就会将数据从 kernel 中拷贝到用户内存

然后 kernel 返回结果,用户进程才解除 block 的状态,重新运行起来

所以,blocking IO 的特点就是在 IO 执行的两个阶段(等待数据和拷贝数据两个阶段)都被 block 了

411 x 431

实际上,除非特别指定,几乎所有的 IO 接口(包括 socket 接口)都是阻塞型的。这给网络编程带来了一个很大的问题。如在调用 recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。

下面使用 python 代码来演示:

服务端:

from socket import *

from threading import Thread

def communicate(conn):

while True:

 

 

try: data = conn.recv(1024) if not data: break conn.send(data.upper()) except ConnectionResetError: break

conn.close() server = socket(AF_INET, SOCK_STREAM)

server.bind(('127.0.0.1', 8080))

server.listen(5)

while True:

print('starting...')

conn,addr = server.accept()

print(addr)

t = Thread(target=communicate, args=(conn,))

t.start() server.close()

客户端:

from socket import *

client = socket(AF_INET, SOCK_STREAM)

client.connect(('127.0.0.1', 8080))

while True:

msg = input("请输入数据:").strip()

if not msg:

 

 

continue

client.send(msg.encode('utf-8'))

data = client.recv(1024)

print(data.decode('utf-8')) client.close()

打开多个客户端,进行发送消息,多发送几次就会出现堵塞的情况:

728 x 297 791 x 323

客户端发送的信息,服务器没有及时返回结果

本文由柠檬班学员库里原创,转载需注明出处!

想了解更多咨询的同学扫描下方二维码,可以加Q群领取学习资料:753665853  备注:

 

最新回复(0)