python并发编程之IO模型

1.什么是IO模型

在计算机系统中,Input/Output(简称 I/O),英语缩写 I/O,是指输入/输出,与计算机中的程序运算(算法)相对。

I/O模型(I/O Model)是操作系统中的一个重要概念,它规定了应用程序与操作系统之间数据交换的方式。

1.1 IO模型的分类

IO模型主要分为五类:

阻塞IO

非阻塞IO

IO复用(select/poll/epoll)

信号驱动IO

异步IO(AIO)

2.阻塞IO模型

阻塞IO(Blocking IO),当一个进程调用了阻塞式 IO 的系统调用函数之后,内核会去查看数据是否准备好,如果数据没有准备好,那么内核就会将这个进程阻塞,当数据准备好并且拷贝到用户态缓冲区后,进程将被唤醒,阻塞状态解除。

下面是使用阻塞IO模型进行文件读写的代码:

def blocking_io():

with open('test.txt', 'rb') as f:

data = f.read()

time.sleep(1)

with open('test.txt', 'wb') as f:

f.write(data)

time.sleep(1)

上面这段代码是使用阻塞IO模型进行文件读写操作,使用方式非常简单,只需要使用 Python 内置函数 open 打开文件,并使用 read 和 write 方法进行读和写操作即可。该函数使用了 time.sleep() 函数模拟了 IO 等待的过程。

3.非阻塞IO模型

非阻塞IO(Non-blocking IO),当一个进程调用非阻塞 IO 的系统调用函数之后,内核立即返回,不会发生进程阻塞,即使数据没有准备好,也会立即返回一个错误码,由于进程不会阻塞,所以 CPU 可以不停地轮询读写操作是否完成,这种方式的缺点就是非常耗费 CPU 资源。

下面是使用非阻塞IO模型进行文件读写的代码:

def non_blocking_io():

f = open('test.txt', 'rb')

data = None

while not data:

try:

data = f.read()

except BlockingIOError:

time.sleep(0.1)

f.close()

f = open('test.txt', 'wb')

while data:

try:

written = f.write(data)

except BlockingIOError:

time.sleep(0.1)

else:

data = data[written:]

f.close()

上面这段代码是使用非阻塞 IO 模型进行文件读写操作,与阻塞 IO 模型不同的是,它在读取和写入数据时使用了 try except 语句,并使用 time.sleep() 函数来降低 CPU 的使用率。

4.IO多路复用模型

IO多路复用(I/O Multiplexing)允许在单个进程中同时处理多个文件描述符的输入/输出请求。通过使用 Select/Poll/Epoll 等系统调用,操作系统内核可以同时监视多个文件描述符的状态,然后在需要读写数据时通知应用程序处理,从而实现了单进程高并发请求的处理。

下面是使用IO多路复用模型进行文件读写的代码:

def io_multiplexing():

f = open('test.txt', 'rb')

p = select.poll()

p.register(f, select.POLLIN)

data = None

while not data:

events = p.poll()

for fd, event in events:

if event & select.POLLIN:

data = f.read()

f.close()

f = open('test.txt', 'wb')

while data:

events = p.poll()

for fd, event in events:

if event & select.POLLOUT:

written = f.write(data)

data = data[written:]

f.close()

上面这段代码是使用 IO 多路复用模型进行文件读写操作,首先使用 select.poll() 函数创建一个对文件描述符的轮询对象,然后使用注册函数 p.register() 注册要进行轮询的文件描述符 f,并设置轮询方式为 POLLIN,表示监测 FD 上是否有可读数据可读取。在轮询到数据可读时,使用 f.read() 读取数据并关闭文件,同时将数据写入同一个文件的同时,使用轮询器上面设置输出模式 POLLOUT 监测是否已就绪,如果就绪,使用 f.write() 函数向文件中写入数据。

5.参考文献

阻塞式与非阻塞式 IO,https://developer.ibm.com/zh/articles/1307_xiawc_io/

I/O多路复用模型,https://www.ibm.com/developerworks/cn/linux/l-async/

后端开发标签