首页 > 编程知识 正文

异步非阻塞io的实现,python 异步框架

时间:2023-05-04 22:23:19 阅读:111277 作者:3726

烽站2009开源实时通信平台获取源代码: SVN check out http://www.Sina.com/://fy 2009.Google code.com/SVN/trunk /

通信服务器通常处理数千个并发用户。 在并发I/o处理用户数据的发送和接收时,必须为每个用户创建一个或两个线程(接收线程和发送线程)。 同步IO的优点是编程简单。 如果用户数量相对较少(例如几个,最多几十个),这是可以接受的,但无法想象为成千上万的用户创建这么多线程。 在任何时刻,每个CPU (对于多核CPU也可以说是一个内核)总是有一个活动线程,以最大限度地提高系统的处理能力。 考虑到每个线程总是有时间等待I/o (处于非活动状态),通常,如果线程数量是CPU数量的两倍,则系统的处理能力通常被大致认为是最高的。 总之,线程数量并不是越多越好,刚开始学习多线程编程的人需要特别注意。 实际上,过多的线程不仅不能提高系统的性能,而且频繁切换线程反而会降低系统的性能。 因此,大规模可伸缩通信服务器几乎无一例外地以异步IO方式处理网络数据的收发。 异步IO机制允许通信服务器更灵活地设计线程模型。 您可以选择单线程,也可以选择可以设置线程数量的线程池或其他多线程方案。 但不幸的是,异步IO通常意味着复杂的状态机管理,大大增加了软件的复杂性。 因此,设计和实现大型、可伸缩的通信服务器不是一件容易的事,也不是处理几个套接字函数调用那么简单。

这里描述了在这个项目中使用异步IO框架,其中在随后的xrpdl中基于实时信号(实时信号)的http://blog.csdn.net/dream freelancer/ARP dl 介绍27的epoll (3358 blog.csdn.net/dream freelancer/archive/2009/07/28/4387375.aspx )和完成端口) Completion Port

操作系统提供的异步I/o服务基本上分为两类。

http

也就是说,如果IO设备(如套接字)当前正在等待接收数据,或者由于发送缓冲区不足而允许发送数据,操作系统将通过一定的方式通知用户程序。 Linux上的实时信号和EPOLL,以及Linux和Windows上的各种Select、Poll等都属于这种情况。

可用通知型(Availability Notification))

用户程序开始决定是否根据需要向IO设备发送异步发送或接收请求,而不考虑当前IO设备的状况。 操作系统不能确保操作立即成功,但会在操作实际完成时通知APP应用程序。 Windows下的完成端口即属于此类。

在所有异步IO模型中,其共同点都是IO设备的状态的监视和报告,该异步IO框架着眼于该共同点,提供统一的IO状态的监视和报告服务,对不同的线程模型具有良好的适应性。

该异步IO框架以Linux下的实时信号和EPOLL等广泛采用的通知型异步IO机制为参考模型,根据完成通知型异步IO的需要进行适当调整。

主要接口的定义和框架的实现如下。

http://www.Sina.com/--APP应用程序实现用于接收异步IO事件的接口。

classaio _ event _ handler _ it : public lookup _ it

{

公共:

virtualvoidon _ AIO _ events (int 32fd,uint32 aio_events,pointer_box_t ex_para=0) ) 0;

(;

参数:软盘、事件相关套接字描述符; aio_events: IO事件。 一次可以传递多个事件。 EPOLL会出现这种情况。 在实时信号和完成端口上,一次只能有一个事件。 ex_para:用于传递pointer_box_t类型的扩展事件参数

是足以存储一个指针的整数类型,对于32位操作系统,其长度必须为32位,而对于64位系统,其长度必须为64位。 端口实现完成后,此参数用于传递OVERLAPPED指针。

完成通知型(Completion Notification--接受或取消指定套接字描述符的异步IO服务请求,并绑定异步IO事件处理程序。 当IO事件发生时,将调用事件处理程序的on_aio_events方法

classaio _ sap _ it : public lookup _ it

{

公共:

//为了支持灵活的线程模型,直接接收服务请求的对象不一定是最终的服务提供者(aio_provider_t,下文),可能

//驻留在线程本地存储(TLS )中的服务代理(aio_proxy_t,如下所示),服务代理接受服务申请时需要

//使用以下参数dest_sap指定最终服务提供者:

否则,该参数为NULL; sp_aioeh_t是上面aio_event_handler_it

   //的Smart Pointer  
   virtual bool register_fd(aio_sap_it *dest_sap, int32 fd, sp_aioeh_t& eh)=0;

          
   virtual void unregister_fd(int32 fd)=0; 

};

异步IO服务提供者aio_provider_t--实现aio_sap_it接口,提供直接或间接的异步IO服务申请(注册),当应用程序(aio_event_handler_it实现者)和aio_provider_t的“心跳线程”(后面给出解释)在同一线程中时(如附图https://p-blog.csdn.net/images/p_blog_csdn_net/dreamfreelancer/EntryImages/20090726/aio-1.JPG所示),应用程序通过直接调用该服务提供者的aio_sap_it注册异步IO服务; 反之, 应用程序通过调用aio_proxy_t的aio_sap_it接口完成服务申请,后者再调用服务提供者的同名接口完成间接服务申请。aio_provider_t还实现了heart_beat_it接口,应用程序通过在“心跳线程”中循环驱动该接口为异步IO服务提供“动力”,监测已登记Socket描述符上的异步IO事件,并调用绑定的aio_event_handler_it将事件通知应用程序。aio_provider_t可在Linux和Windows间移值; 为实时信号,EPOLL和Widnows下的完成端口提供尽可能一致的访问接口。

aio_provider_t并没有被实现成Singleton,因此,同一进程中根据需要创建多个provider实例,分别管理各自的Sockets是允许的,它们当然可以有不同的“心跳线程”。但彼此间不应该有过多的逻辑耦合。

异步IO代理aio_proxy_t--实现aio_sap_it接口,当应用程序线程需要从aio_provider_t的“心跳线程”之外申请异步IO服务时(如附图https://p-blog.csdn.net/images/p_blog_csdn_net/dreamfreelancer/EntryImages/20090726/aio-2.JPG所示),需通过该代理对象申请服务。该代理驻留在应用程序线程局部存储(TLS)中。通过该代理对象申请异步IO服务时,用户事件处理对象(实现了aio_event_handler_it接口),将被注册到该代理对象中,另外再自动生成一个实现了aio_event_handler_it接口的“存根对象”(aio_stub_t),并将后者注册到aio_provider_t的心跳线程中,当“存根对象”收到IO事件时,通过高效的oneway_pipe_t(http://blog.csdn.net/DreamFreeLancer/archive/2009/06/01/4231151.aspx)将事件跨线程送给aio_proxy_t, 代理对象找到注册的用户事件处理器,并在应用程序线程中调用其aio_event_handler_it接口。
总之,aio_provider_t接合aio_proxy_t和aio_stub_t,提供了通用,灵活,可移植的异步IO服务框架。有关该框架基于实时信号,EPOLL和完成端口的一些实现细节,将在后续xrpdl中说明。

 

重要参数:

static sp_aiop_t aio_provider_t::s_create(uint16 max_fd_count=AIO_DEF_MAX_FD_COUNT, bool rcts_flag=false); 

max_fd_count参数影响系统的并发容量, 缺省值是1024,就是说通过该服务管理的IO设备(或Socket)不能超过这个数,否则,将出错。显然,对于大于通讯服务器,这个值偏小,初始化aio_provider对象时,需指定一个足够大的值,最大当然不超过65535,那是操作系统的上限。对于Windows系统,该值也不能太小,不能小于512(实际精确值应是488,详细原因参:http://blog.csdn.net/DreamFreeLancer/archive/2009/07/09/4335571.aspx),否则,该服务将完全不能工作。

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。