百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

python--io多路复用之select实现(selector多路复用)

toyiye 2024-08-27 22:09 4 浏览 0 评论

1、I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

2、I/O多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理。

select

select是通过系统调用来监视一组由多个文件描述符组成的数组,通过调用select()返回结果,数组中就绪的文件描述符会被内核标记出来,然后进程就可以获得这些文件描述符,然后进行相应的读写操作

select的实际执行过程如下:

1、select需要提供要监控的数组,然后由用户态拷贝到内核态。

2、内核态线性循环监控数组,每次都需要遍历整个数组。

3、内核发现文件描述符状态符合操作结果,将其返回。

所以对于我们监控的socket都要设置为非阻塞的,只有这样才能保证不会被阻塞。

优点

基本各个平台都支持

缺点

1、每次调用select,都需要把fd集合由用户态拷贝到内核态,在fd多的时候开销会很大

2、单个进程能够监控的fd数量存在最大限制,因为其使用的数据结构是数组。

3、每次select都是线性遍历整个数组,当fd很大的时候,遍历的开销也很大

python使用select

语法:r_list, w_list, e_list = select.select( rlist, wlist, errlist [,timeout] )

说明详解:

rlist,wlist和errlist均是waitable object; 都是文件描述符,就是一个整数,或者一个拥有返回文件描述符的函数fileno()的对象。

rlist: 等待读就绪的文件描述符数组

wlist: 等待写就绪的文件描述符数组

errlist: 等待异常的数组

在linux下这三个列表可以是空列表,但是在windows上不行

当rlist数组中的文件描述符发生可读时(调用accept或者read函数),则获取文件描述符并添加到r数组中。

当wlist数组中的文件描述符发生可写时,则获取文件描述符添加到w数组中

当errlist数组中的文件描述符发生错误时,将会将文件描述符添加到e队列中

当超时时间没有设置时,如果监听的文件描述符没有任何变化,将会一直阻塞到发生变化为止

当超时时间设置为1时,如果监听的描述符没有变化,则select会阻塞1秒,之后返回三个空列表。 如果由变化,则直接执行并返回。

一、基于select实现的IO多路复用的基础实例:

io_server.py

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 """
 4 IO多路复用服务器端
 5 """
 6 import socket
 7 
 8 sk1 = socket.socket()
 9 sk1.bind(('127.0.0.1', 8001))
10 sk1.listen(5)
11 
12 sk2 = socket.socket()
13 sk2.bind(('127.0.0.1', 8002))
14 sk2.listen(5)
15 
16 sk3 = socket.socket()
17 sk3.bind(('127.0.0.1', 8003))
18 sk3.listen(5)
19 
20 inputs = [sk1, sk2, sk3]
21 import select
22 
23 while True:
24 #[sk1, sk2, sk3],select内部启动监听sk1, sk2, sk3三个对象,一旦某个句柄发生变化
25 #如果有人用sk1
26 #r_list = [sk1, sk2, sk3]
27 r_list, w_list, e_list = select.select(inputs, [], [], 1)
28 print(r_list)
29 for sk in r_list:
30 #每一个连接对象
31 conn, address = sk.accept()
32 conn.sendall(bytes('Hello', encoding='utf-8'))
33 conn.close()

io_client.py

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 """
 4 客户端1,请求8001端口
 5 """
 6 import socket
 7 
 8 ck = socket.socket()
 9 ck.connect(('127.0.0.1', 8001))
10 
11 content = str(ck.recv(1024), encoding='utf-8')
12 print(content)

二、IO多路复用服务器端升级改造后的代码实现

io_server2.py

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 """
 4 IO多路复用服务器端升级改造
 5 """
 6 
 7 import socket
 8 import select
 9 
10 sk = socket.socket()
11 
12 sk.bind(('127.0.0.1', 8001))
13 sk.listen()
14 
15 inputs = [sk,]
16 while True:
17 r_list, w_list, e_list = select.select(inputs, [], [], 1)
18 print('正在监听的socket对象:%d' % len(inputs))
19 for sk_or_conn in r_list:
20 #每一个连接对象
21 if sk_or_conn == sk:
22 #表示有新用户来连接
23 conn, address = sk.accept()
24 inputs.append(conn)
25 else:
26 #有老用户发消息了
27 try:
28 data_bytes = sk_or_conn.recv(1024)
29 except Exception as ex:
30 #如果有用户终断连接,则移除句柄
31 inputs.remove(sk_or_conn)
32 else:
33 #用户正常发送信息
34 data_str = str(data_bytes, encoding='utf-8')
35 sk_or_conn.sendall(bytes(data_str + '好', encoding='utf-8'))
36 
37 for sk in e_list:
38 inputs.remove(sk)

三、IO多路复用服务器端升级改造,读、写分离

io_server3.py

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 """
 4 IO多路复用服务器端升级改造,读、写分离
 5 """
 6 
 7 import socket
 8 import select
 9 
10 sk = socket.socket()
11 sk.bind(('127.0.0.1', 8001))
12 sk.listen()
13 
14 inputs = [sk,]
15 outputs = []
16 message_dict = {}
17 
18 while True:
19 
20 r_list, w_list, e_list = select.select(inputs, outputs, inputs, 1)
21 
22 print('正在监听的socket对象:%d' % len(inputs))
23 for sk_or_conn in r_list:
24 #每一个连接对象
25 if sk_or_conn == sk:
26 #表示有新用户来连接
27 conn, address = sk.accept()
28 inputs.append(conn)
29 #将连接的用户添加到字典中
30 message_dict[conn] = []
31 else:
32 #有老用户发消息了
33 try:
34 data_bytes = sk_or_conn.recv(1024)
35 except Exception as ex:
36 #如果有用户终断连接,则移除句柄
37 inputs.remove(sk_or_conn)
38 else:
39 # 用户正常发送信息
40 data_str = str(data_bytes, encoding='utf-8')
41 message_dict[sk_or_conn].append(data_str) #将用户发送过来的信息存在在字典中
42 # sk_or_conn.sendall(bytes(data_str + '好', encoding='utf-8'))
43 outputs.append(sk_or_conn)
44 
45 #写操作
46 for sk_out in w_list:
47 recv_data = message_dict[sk_out][0] #从字典中获取信息数据
48 del message_dict[sk_out][0] #获取数据后,清空字典,等待存储下次的数据
49 sk_out.sendall(bytes(recv_data + '好', encoding='utf-8'))
50 outputs.remove(sk_out)
51 
52 for sk in e_list:
53 inputs.remove(sk)

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码