Python 中 IO多路复用

Kotlin原生AI Agent框架Koog:为JVM开发者打造类型安全、企业级智能体开发方案 AI Agent作为当前人工智能应用开发的核心范式,通过赋予大语言模型(LLM)自主规划、工具调用和环境交互能力,正在重塑软件智能化进程。其技术原理基于智能体架构,通过提示工程、函数调用和记忆机制,将LLM从单纯的文本生成器转变为能够执行复杂任务的工作流引擎。这一技术价值在于显著降低了构建智能应用的开发门槛,同时保持了高度的灵活性和可扩展性。在实际应用场景中,AI Agent广泛落地于智能客服、代码助手、数据分析自动化等领域,成为连接大模型能力与具体业务需求的关键桥梁。本文聚焦的Koog框架,正是针对JVM 阅读详情

IO多路复用

  • 大多数操作系统都支持select和poll
  • Linux 2.5+ 支持epoll
  • BSD、Mac支持kqueue
  • Solaris实现了/dev/poll
  • Windows的IOCP

Python的select库实现了select、poll系统调用,这个基本上操作系统都支持。部分实现了epoll。它是底层的IO多路复用模块

开发中的选择

  1. 完全跨平台,使用select、poll。但是性能较差
  2. 针对不同操作系统自行选择支持的技术,这样做会提高IO处理的性能

select维护一个文件描述符数据结构,单个进程使用有上限,通常是1024,线性扫描这个数据结构。效率低。
pool和select的区别是内部数据结构使用链表,没有这个最大限制,但是依然是线性遍历才知道哪个设备就绪了
epool使用事件通知机制,使用回调机制提高效率。

select/pool还要从内核空间复制消息到用户空间,而epoll通过内核空间和用户空间共享一块内存来减少复制

selectors库

3.4版本提供selectors库,高级IO复用库

类层次结构︰
BaseSelector
+-- SelectSelector		实现select
+-- PollSelector		实现poll
+-- EpollSelector		实现epoll
+-- DevpollSelector		实现devpoll
+-- KqueueSelector		实现kqueue

selectors.DefaultSelector返回当前平台最有效、性能最高的实现。
但是,由于没有实现Windows下的IOCP,所以,Windows下只能退化为select

  • 在selects模块源码最下面有如下代码
# Choose the best implementation, roughly:
# epoll|kqueue|devpoll > poll > select.
# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
if 'KqueueSelector' in globals():
	DefaultSelector = KqueueSelector
elif 'EpollSelector' in globals():
	DefaultSelector = EpollSelector
elif 'DevpollSelector' in globals():
	DefaultSelector = DevpollSelector
elif 'PollSelector' in globals():
	DefaultSelector = PollSelector
else:
	DefaultSelector = SelectSelector
  • 事件注册
class SelectSelector(_BaseSelectorImpl): 
	"""Select-based selector."""
	def register(fileobj, events, data=None) -> SelectorKey: pass

为selector注册一个文件对象,监视它的IO事件。返回SelectKey对象。

  • fileobj 被监视文件对象,例如socket对象
  • events 事件,该文件对象必须等待的事件
  • data 可选的与此文件对象相关联的不透明数据,例如,关联用来存储每个客户端的会话ID,关联方法。通过这个参数在关注的事件产生后让selector干什么事
Event常量含义
EVENT_READ可读 0b01,内核已经准备好输入输出设备,可以开始读了
EVENT_WRITE可写 0b10,内核准备好了,可以往里写了

selectors.SelectorKey 有4个属性:

  1. fileobj 注册的文件对象
  2. fd 文件描述符
  3. events 等待上面的文件描述符的文件对象的事件
  4. data 注册时关联的数据

练习:IO多路复用TCP Server

完成一个TCP Server,能够接受客户端请求并回应客户端消息

import selectors
import socket

# 构建本系统最优Selector
s = selectors.DefaultSelector() # 拿到selector

# 准备类文件对象
server = socket.socket()
server.bind(('127.0.0.1', 9999))
server.listen()

# 官方建议采用非阻塞ID
server.setblocking(False)

# 回调函数,sock的读事件
# 形参自定义
def accept(sock:socket.socket, mask:int):
	"""mask:事件的掩码"""
    conn, raddr = sock.accept()
    conn.setblocking(False) # 非阻塞
    key = s.register(conn, selectors.EVENT_READ, recv) # 读和写可同时监控, selectors.EVENT_READ | selectors.EVENT_WRITE
    print(key)
    
# 回调函数
def recv(conn:socket.socket, mast:int):
    data = conn.recv(1024)
    print(data)
    msg = 'Your msg = {} from {}'.format(data.decode(), conn.getpeername()).encode()
    conn.send(msg)

# 注册关注的类文件对象和其事件们 'fileobj', 'fd', 'events', 'data'
# 返回SelectorKey对象
key = s.register(server, selectors.EVENT_READ, accept) #socket fileobject
print(key)
print(key.__class__.mro())

while True:
	# 监听注册的对象的事件,发生被关注事件则返回events
    events = s.select() # epoll select, 默认是阻塞的
    # 当你注册的文件对象们, 这其中的至少一个对象关注的时间就绪了,就不阻塞了
    print(events) # [(key, mask)]

    for key, mask in events:
    	# key.data => accept; key.fileobj => sock
        # 每一个event都是某一个被观察的就绪的对象
        print(type(key), type(mask))
        print(key.data)
        key.data(key.fileobj, mask)

实战:IO多路复用群聊软件

将ChatServer改写成IO多路复用的方式
不需要启动多线程来执行socket的accept、recv方法了

import socket
import threading
import selectors
import logging

FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO)


class ChatServer:
    def __init__(self, ip='127.0.0.1', port=9999):
        self.sock = socket.socket()
        self.addr = ip, port
        self.event = threading.Event()

        # 构建本系统最优Selector
        self.selector = selectors.DefaultSelector()

    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        self.sock.setblocking(False)

        # 注册sock的被关注事件,返回SelectorKey对象
        # key记录了fileobj, fileobj的fd, events, data
        key = self.selector.register(self.sock, selectors.EVENT_READ, self.accept)
        logging.info(key) # 只有一个
        # self.acceptkey = key

        # select用的
        threading.Thread(target=self.select, name='select', daemon=True).start()

    def select(self):
        while not self.event.is_set():
            # 监听注册的对象的事件,发生被关注事件则返回events
            events = self.selector.select() # 阻塞
            print(events)  # [(key, mask)]
            for key, mask in events:
                # key.data => accept; key.fileobj => sock
                key.data(key.fileobj, mask) # select线程

    # 回调函数,sock的读事件
    # 形参自定义
    def accept(self, sock:socket.socket, mask):
        """mask:事件的掩码"""
        conn, raddr = self.sock.accept()
        conn.setblocking(False) # 非阻塞

        key = self.selector.register(conn, selectors.EVENT_READ, self.recv)
        logging.info(key) #n个

    # 回调函数
    def recv(self, conn:socket.socket, mask):
        data = conn.recv(1024)

        if data.strip() == b'quit' or data.strip() == b'':
            # bye
            self.selector.unregister(conn)
            conn.close()
            return

        for key in self.selector.get_map().values():
            # if key.fileobj is self.sock :continue
            # print(self.recv is key.data) # False
            # print(self.recv == key.data)
            if key.data == self.recv: # key.data 注册时注入的绑定的对象
                s = key.fileobj
                msg = 'Your msg = {} from {}'.format(data.decode(), conn.getpeername()).encode()
                s.send(msg)

    def stop(self):
        self.event.set()

        fs = []
        for key in self.selector.get_map().values():
            fs.append(key.fileobj)
        for f in fs:
            self.selector.unregister(f)
            f.close()

        self.selector.close()

if __name__ == '__main__':
    cc = ChatServer()
    cc.start()
    while True:
        cmd= input('>>').strip()
        if cmd == 'quit':
            cc.stop()
            break
        logging.info(threading.enumerate())

本例只完成基本功能,其他功能如有需要,请自行完成。
注意使用IO多路复用,使用了几个线程?
特别注意key.data == self.recv

总结

使用 IO多路复用 +(select、epoll) 并不一定比 多线程 + 同步阻塞IO 性能好,其最大优势可以处理更多的连接

  • 多线程 + 同步阻塞IO模式
    开辟太多线程,线程开辟、销毁开销还是较大,倒是可以使用线程池;线程多,线程自己使用的内存也很可观;多线程切换时要保护现场和恢复现场,线程过多,切换会占用大量的时间

  • 连接较少,多线程 + 同步阻塞IO模式比较适合,效率也不低

  • 如果连接非常多,对服务端程序来说,IO并发还是比较高的,这时候,开辟太多线程其实也不是很划算,这时候IO多路复用或许是更好的选择,使用epoll

SAP FICO应付票据平台开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行) 阅读详情

相关推荐

如何在高版本的ubuntu系统里安装gcc4.1.2

1、下载安装包,一共五个http://archive.ubuntu.com/ubuntu/pool/universe/g/gcc-4.1/,根据计算机系统位数   进行下载,64位下载amd64结尾的。开头分别是cpp-4.1_4.1.2、g++-4.1_4.1.2、gcc-4.1-base_4.1.2、gcc-     4.1_4.1.2、libstdc++6-4.1 2、使用sudo d

lsr_fighting的博客 1931

python笔记(十九):IO多路复用

传统的编程是如下线性模式的:开始—>代码块A—>代码块B—>代码块C—>代码块D—>…—>结束每一个代码块里是完成各种各样事情的代码,但编程者知道代码块A,B,C,D…的执行顺序,唯一能够改变这个流程的是数据。输入不同的数据,根据条件语句判断,流程或许就改为A—>C—>E…—>结束。每一次程序运行顺序或许都不同,但它的控制流程是由输入数据和你编写的程序决定的。如果你知道这个程序当前的运行状态(包括输入数据和程序本身),那你就知道接下来甚至一直到结束它的运行流程。

baikai666的博客 751

Ubuntu桌面消失?可能是lightdm配置在捣鬼:详细解析/etc/lightdm.conf的优先级机制与实战修复

本文详细解析了Ubuntu系统因lightdm显示管理器配置错误导致桌面消失的问题。通过分析/etc/lightdm.conf的优先级加载机制,提供了从systemctl诊断、调试模式运行到实战修复配置语法错误(如缺失[Seat:*]组)的完整方案。文章还探讨了在系统无法启动时使用chroot或恢复模式进行高级救援,并对比了lightdm与gdm3在NVIDIA驱动环境下的不同表现,帮助用户高效恢复图形界面。

weixin_29313547的博客 420

Python语言入门:I/O多路复用学习

在argv3的监听列表中,如果在跟某个socket连接通信过程中出了错误,就会把错误的句柄加到eList ,所以在加个判断,当某个socket连接通信过程中出了错误,就把这个错误的连接对象在各个列表和字典中删除。当客户端有新的连接请求过来时,select捕捉到服务端句柄发生变化,把变化的句柄加入到rlist,所以这时r == sk,接收这个链接并把句柄加入到inputs列表,sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象。

hdxx2022的博客 255

TGK-planner编译报错PLUGINLIB_EXPORT_CLASS解决

TGK-planner编译报错解决。

latter97的博客 857

Stata实战入门:从数据导入到基础分析的全流程指南

本文提供了Stata实战入门的全流程指南,从数据导入、清洗到基础分析和可视化,帮助初学者快速掌握Stata的核心功能。通过详细的步骤和实用技巧,读者可以高效完成数据处理、变量操作、描述性统计和回归分析等任务,提升数据分析效率。

weixin_28327051的博客 383

Python语言 I/O多路复用浅谈

在argv3的监听列表中,如果在跟某个socket连接通信过程中出了错误,就会把错误的句柄加到eList ,所以在加个判断,当某个socket连接通信过程中出了错误,就把这个错误的连接对象在各个列表和字典中删除。当客户端有新的连接请求过来时,select捕捉到服务端句柄发生变化,把变化的句柄加入到rlist,所以这时r == sk,接收这个链接并把句柄加入到inputs列表,sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象。

hdxx2022的博客 228

手把手教您windows如何正确的开启局域网共享,如何解决“没权限、空密码访问等诸多问题”,含手动操作教程 + 傻瓜式一键设置工具(局域网共享+打印机管理),二选一总有一款能满足您!

😫 Windows共享总失败?别抓狂!这篇教程带你破解“空密码”访问的核心难题 🔑,四步搞定所有设置。文末还附赠“一键修复”神器 🚀,让文件共享丝滑如德芙!

XiaoqiangClub的博客 1452

Python-IO多路复用

Python 是实现 IO 多路复用

蓝魔的博客 1129

0基础学习diffusion_model扩散模型【易理解的公式推导】Denoising Diffusion Probabilistic Models

去噪扩散概率模型。本文是笔者在学习扩散模型时的一些笔记与心得,在公式推导过程中能够保证自己是一步一步去推导并且理解了的。概述是我认为比较重要的部分能够帮助理解公式的推导,具体的公式推导在每一小节中进行。1、扩散过程:如上图所示,扩散过程为从右到左X0→XTX0​→XT​的过程,表示对图片逐渐加噪,且Xt1X_{t+1}Xt1​是在XtX_{t}Xt​加躁得到的,其只受XtX_{t}Xt​的影响,因此扩散过程是一个马尔科夫过程。X0X_0。

zik的博客 2397

项目经理必看:如何建立高效的相关方沟通机制?

你是否遇到过这样的场景?客户突然说“这不是我要的”,开发团队抱怨“需求总变”,高层追问“进度滞后为什么不早说”?这些问题的根源往往是——相关方沟通机制失效。本文聚焦“如何建立高效沟通机制”,覆盖从识别相关方到持续优化的全流程,适用于IT、产品、工程等各类项目。本文将按“理解问题→拆解核心概念→掌握工具方法→实战落地→未来趋势”的逻辑展开,重点讲解“相关方分析矩阵”“沟通计划表”等实用工具,并用“组织生日派对”的案例贯穿全文,让抽象概念变得可感知。相关方识别:用“权力/利益矩阵”找对人(像派对邀请关键客人)

项目管理的博客 1295

Python:关于I/O多路复用

转自:微点阅读 https://www.weidianyuedu.com一、I/O多路复用概念:监听多个描述符的状态,如果描述符状态改变,则会被内核修改标志位,从而被进程获取进而进行读写操作二、select,poll,epollselect模块,提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。Windows Python:提供: selectMac Python:提供: selectLinux Python:提供: select

xiaoweids的博客 267

【ACP】2025-最新-疑难题解析- 练习二汇总

全球加速是优化公网访问的,负载均衡是分发流量的,公网 NAT 网关是处理公网 IP 的,高速通道是建私网连接但不直接提供固定私网地址功能。C 是客户端加密方式,D 是 ECS 云盘加密,都不属于 OSS 服务器端加密。某企业想使用云服务器 ECS + 负载均衡 SLB + 弹性伸缩 (Auto Scaling) 的架构搭建一个企业级门户网站,技术负责人对于负载均衡和弹性伸缩配合使用没有经验,于是将他理解的两种产品配合使用的一些技术细节列成了一个表单,并请作为架构师的您帮他做一下鉴别,以下哪些项是正确的?

jundao1997的专栏 293

python的io多路复用_python之路10:IO多路复用

IO模型select模块selectors模块IO模型网络IO的本质是socket的读取,socket在linux系统中被抽象为流,IO可以理解为对流的操作.对于一次IO访问,数据会先被拷到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间,所以说当一个read操作发生时,它会经理两个阶段:第一阶段:等待数据准备;第二阶段:将数据从内核拷贝到进程中对socket流而言:...

weixin_39822443的博客 132

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

python 多路复用io_详解Python IO口多路复用

详解Python IO口多路复用,进程,数据,区别,操作,定义详解Python IO口多路复用易采站长站,站长之家为您整理了详解Python IO口多路复用的相关内容。1、blocking和non-blocking的区别:调用blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在kernel还准备数据的情况下会立刻返回。2、synchronous IO和...

weixin_30456719的博客 225

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

python 多路复用io_python IO多路复用

python之IO多路复用1. 多路复用概念:监听多个描述符(文件描述符(windows下暂不支持)、网络描述符)的状态,如果描述符状态改变 则会被内核修改标志位,进而被进程获取进而进行读写操作I/O多路复用是用于提升效率,单个进程可以同时监听多个网络连接IOI/O是指Input/OutputI/O多路复用,通过一种机制,可以监视多个文件描述符,一旦描述符就绪(读就绪和写就绪),能通知程序进行相应...

weixin_33917277的博客 881

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

python 多路复用io_python之路10:IO多路复用

IO模型select模块selectors模块IO模型网络IO的本质是socket的读取,socket在linux系统中被抽象为流,IO可以理解为对流的操作.对于一次IO访问,数据会先被拷到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间,所以说当一个read操作发生时,它会经理两个阶段:第一阶段:等待数据准备;第二阶段:将数据从内核拷贝到进程中对socket流而言:...

weixin_39809175的博客 109

Python 信号驱动式IO、异步IO、IO多路复用

这段代码是IO多路复用服务器的经典实现,能高效处理多个客户端的连接和数据收发。通过select和非阻塞IO,单进程即可实现高并发网络服务。说明通过监听所有socket的可读事件。新连接加入inputs,断开连接移除inputs。单进程即可高效管理多个客户端。信号驱动IO通过信号机制实现异步IO事件通知,主程序无需阻塞等待。需要注册信号处理函数、设置fd所有者和异步IO标志。适合底层高性能场景,Python中较少直接使用。说明需要底层操作系统支持,Python中很少直接用。

qq_37805832的博客 834

python IO多路复用

文章目录python中IO多路复用1. select2. poll3. epoll python中IO多路复用 IO多路复用中包括 select、pool、epoll,这些都是阻塞IO 1. select 功能: 监控(关注)多个IO, 如果某个IO处于就绪状态 则立即返回、通知应用程序 实现 rlist = [fd,] #关注读事件IO列表 wlist = [fd,] #关注写事...

qq_36881091的博客 348

Python 并发 - io多路复用

文章目录前言一、io多路复用优势二、 三种io多路复用模型 前言 python中的并发框架 tornado 异步方式基于epoll的io多路复用模式保证 单线程内的高并发,本篇对 io多路复用 模式做个总结 一、io多路复用优势 在 socket 编程中, 有阻塞 io模型和 非阻塞io模型,两者的区别在于 connect,accept, accept, recv等 一些列socket操作是否阻塞,那么两种模式有什么区别呢? 在阻塞io方式下, 一般采用多线程或者多进程的方式保证服务器的并发, 这种方

非-浪的博客 355

python IO多路复用(异步IO,同步IO,select,poll,epoll)

概述 IO多路复用是IO模式的一种,是一种单线程处理多并发的IO操作的方案,其他IO操作方案分别有 : 阻塞 I/O(blocking IO) 非阻塞 I/O(nonblocking IO) I/O 多路复用( IO multiplexing) 异步 I/O(asynchronous IO) IO多路复用其实就是我们说的select,poll,epoll,它的基本原理就是select,poll,e...

weixin_42563968的博客 469

python io多路复用框架_Python IO多路复用

IO多路复用检测多个socket是否已经发生变化,(是否已经连接成功/是否已经获得数据)(可读/可写)实现:IO多路复用 select模块操作系统检查socket是否发生变化,有三种模式:select:最多1024个socket;循环去检测poll:不限制监听socket个数;循环去检测(水平触发)epoll:不限制监听socket个数;回调方式(边缘触发)python模块:select.sel...

weixin_40006265的博客 191

python3的IO多路复用

五种IO模型:阻塞IO;非阻塞IO;IO多路复用;信号驱动IO;异步IO 为了提高并发能力,可以采用多进程/多线程的方式实现,但是进程和线程的创建开销较大,所以一般采用IO多路复用来提高并发。 IO多路复用:仅仅在内核等待数据时阻塞,一旦socket返回了可读之后,调用recvfrom直接就能拿到数据,单进程可以同时处理多个socket请求,python3中selectors模块实现IO多路复用 ...

weixin_43394769的博客 368

python 多路复用io_python11-IO多路复用

IO多路复用socket在客户端与服务端建立连接后,之后的请求都需要等待原生的socket服务端只能在同一时刻处理一个请求IO多路复用:可以监听多个文件描述符(socket对象),一旦文件描述符的状态出现变化,就会感知到一旦有人给服务器发送请求,服务端的socket就会发生变化或服务端通过Socket给客户端发送数据,服务端的socket也会发生变化让socket监听多个端口原生的socket只能...

weixin_42320061的博客 237

python io多路复用_python实现IO多路复用 --- selector

IO多路复用O多路复用技术是使用一个可以同时监视多个IO阻塞的中间人去监视这些不同的IO对象,这些被监视的任何一个或多个IO对象有消息返回,都将会触发这个中间人将这些有消息IO对象返回,以供获取他们的消息。使用IO多路复用的优点在于进程在单线程的情况下同样可以同时处理多个IO阻塞。与传统的多线程/多进程模型比,I/O多路复用系统开销小,系统不需要创建新的进程或者线程,也不需要维护这些进程和线程的运...

weixin_39962285的博客 234

Python之IO多路复用

一、IO模型介绍 二、阻塞IO(Blocking IO) 三、非阻塞IO(non-Blocking IO) 四、多路复用IO(IO multiplexing)(重点) 1.Python中的select模块 2.select网络IO示例 五、异步IO(Asynchronous IO) 六、IO模型比较分析 七、selectors模块 1.select ...

weixin_30610755的博客 233
上一篇: IO多种概念
下一篇: Python -- asyncio库
鹿夏
博客等级 码龄8年 24粉丝 105原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值