Python 支持重启的异步IO的简单示例
|
对python这个高级语言感兴趣的小伙伴,下面一起跟随脚本之家 jb51.cc的小编两巴掌来看看吧! 摘要
这是一份从Python3.3开始的Python3异步I/O提议。研究从PEP 3153缺失的具体提议。 这提议包括了一个可插入式的事件循环API,传输和与Twisted相似的协议抽象,以及来自(PEP 380) 基于yield的更高级的调度器。一份作品里的参考实现,它的代码命名为Tulip(Tulip的repo的链接放在文章最后的参考文献分段里)。 介绍
事件循环常用于互操作性较高的地方。对于像Twisted、Tornado或者ZeroMQ这类(基于Python3.3的)框架,它应该是容易去根据框架的需求通过轻量级封装或者代理去适配默认的事件循环实现,或者是用它们自己的事件循环实现去替代默认的实现。(一些像Twisted的框架,拥有多种的事件循环实现。由于这些实现都具有统一的接口,所以这应该不会成为问题。) 事件循环甚至有可能存在两个不同的第三方框架交互,通过共享默认事件循环实现(各自使用自己的适配器),或者是通过共享其中一个框架的事件循环实现。在后者,两种不同级别的适配可能会存在(从框架A的事件循环到标准事件循环接口,然后从标准的再到框架B的事件循环)。被使用的事件循环实现应该在主程序的控制之下(尽管提供了事件循环可以选择的默认策略)。 因此,两个单独的API被定义: 获取和设置当前事件的循环对象; 一个确认事件循环对象的接口和它的最低保证 一个事件循环实现可能提供额外的方法和保证。 事件循环接口不取决于产量,相反,它使用一个回调,额外接口(传输协议和协议)以及期货(?)的组合。后者类似于在PEP3148中定义的接口,但有不同的实现而且不绑定到线程。特别是,它们没有wait()方法,用户将使用回调。 对于那些不喜欢用回调函数的人(包括我),(Python)提供了一个写异步I/O代码的调度器作为协同程序,它使用了PEP 380的yield from表达式。这个调度器并不是可插入的;可插入性存在于事件循环级别,同时调度器也应该工作在任何符合标准的事件循环实现上。 对于那些在使用协同程序和其他异步框架的代码的互操作性,调度器有一个行为上类似Future的Task类。一个在事件循环级别进行交互操作的框架能够通过加入一个回调函数到Future中,同时等待一个Future来完成。同样的,调度器提供一个操作来挂起协同程序,直到回调函数被调用。 通过事件循环接口来为线程间交互操作提供限制;(Python里)有一个API能够提交一个函数到一个能够返回兼容事件循环的Future的执行器(看 PEP 3148)。 没有目的的
像Stackless Python或 greenlets/gevent 的系统互操作性不是本教程的目的。 规范
依赖
Python3.3是必需的。不需超过Python3.3范围的新语言或标准库。不需要第三方模块或包。 模块命名空间
这里的规范会放在一个新的顶层包。不同的组件会放在这个包的不同子模块里。包会从各自的子模块中导入常用的API,同时使他们能作为包的可用属性(类似电子邮件包的做法)。 顶层包的名字目前还没指定。参考实现使用“tulip”来命名,但是这个名字可能会在这个实现加入到标准库的时候改变为其他更为烦人的名字(有希望在Python3.4中)。 在烦人的名字选好之前,这篇教程会使用“tulip”作为顶层包的名字。假定没有给定模块名的类和函数都通过顶层包来访问。 事件循环策略:获取和设置事件循环
要获取当前的事件循环,可以使用get_event_loop()。这函数返回一个在下面有定义的EventLoop类的实例或者一个等价的对象。get_event_loop()可能根据当前线程返回不同的对象,或者根据其他上下文的概念返回不同对象。 要设置当前事件循环,可以使用set_event_loop(event_loop),这里的event_loop是EventLoop类的实例或者等价的实例对象。这里使用与get_event_loop()相同的上下文的概念。 还有第三个策略函数:new_event_loop(),有利于单元测试和其他特别的情况,它会创建和返回一个新的基于该策略的默认规则的EventLoop实例。要使它成为当前的事件循环,你需要调用set_event_loop()。 要改变上述三个函数的工作方式(包括他们的上下文的概念),可以通过调用set_event_loop_policy(policy),其中参数policy是一个事件循环策略对象。这个策略对象可以是任何包含了类似上面描述的函数表现(get_event_loop(),set_event_loop(event_loop)和new_event_loop())的对象。默认的事件循环策略是DefaultEventLoopPolicy类的一个实例。当前事件循环策略对象能够通过调用get_event_loop_policy()来取回。 一个事件循环策略没强制要求只能有一个事件循环存在。默认的事件循环策略也没强制要求这样做,但是它强制要求每个线程只能有一个事件循环。 事件循环接口
关于时间:在 Python 中,所有的超时(timeout),间隔(interval)和延时(delay)都是以秒来计算的,可以是整型也可以是浮点型。时钟的精准度依赖于具体的实现;默认使用 time.monotonic()。 关于回调(callbacks)和处理函数(handlers):如果一个函数接受一个回调函数和任意个数的变量作为参数,那么你也可以用一个处理函数对象(Handler)来替换回调函数。这样的话就不需要再传递那些参数。这个处理函数对象应该是一个立即返回的函数(fromcall_soon()),而不是延迟返回的(fromcall_later())。如果处理函数已经取消,那么这个调用将不起作用。 一个符合标准的事件循环对象拥有以下的方法: run()。 执行事件循环,知道没啥好做了。具体的意思是: 除了取消调用外,没有更多通过call_later(),call_repeatedly(),call_soon(),orcall_soon_threadsafe()这些方法调度的调用。 没有更多的注册了的文件描述符。 当它关闭的时候会由注册方来注销文件描述符。 备注:直到遇到终止条件或者调用stop(),run()会一直阻塞。 备注: 如果你使用call_repeatedly()来执行一个调用,run()不会在你调用stop()前退出。 需要详细说明: 有多少类似的真正需要我们做的? run_forever()。直到调用stop()前一直运行事件循环。 run_until_complete(future,timeout=None)。在Future完成前一直运行事件循环。如果给出了timeout的值,它会等待timeout的时间。 如果Future完成了,它的结果会返回 或者它的异常抛出;如果在超时前完成Future, 或者stop()被调用,会抛出TimeoutError (但Future不会被取消). 在事件循环已经在运行的时候,这个方法不能调用。 备注: 这个API更多用来做测试或者类似的工作。 它不应该用作从yield from 表达式的future替代品或其他等待一个Future的方法。 (例如 注册一个完成的回调)。 run_once(timeout=None)。运行事件循环一段事件。 如果给出了timeout的值, I/O轮询会阻塞一段时间; 否则,I/O轮询不会受时间约束。 备注:准确来说,这里做了多少工作是根据具体实现的。 一个约束是:如果一个使用call_soon()来直接调度自己,会导致死顺坏,run_once()仍然会返回。 stop()。尽可能快地停止事件循环。随后可以使用run()重启循环(或者的一个变体)。 备注: 有多块来停止是根据它具体实现。所有在stop()前已经在运行的直接回调函数必定仍在运行,但是在stop()调用后的调度的回调函数(或者延迟运行的)不会运行。 close()。关闭事件循环,释放它所保持的所有资源,例如被epoll()或kqueue()使用的文件描述符。这个方法不应该在事件循环运行期间调用。它可以被多次调用。 call_later(delay,callback,*args)。为callback(*args)安排延迟大约delay秒后调用,一旦,除非被取消了。返回一个Handler对象代表回调函数,Handler对象的cancel()方法常用来取消回调函数。 call_repeatedly(interval,**args)。和call_later()类似,但是会在每个interval秒中重复调用回调函数,直到返回的Handler被取消。第一次调用是在interval秒内。 call_soon(callback,*args)。类似call_later(0,*args)。 call_soon_threadsafe(callback,*args)。类似call_soon(callback,*args),但是当事件循环在阻塞等待IO的时候在另外的线程调用,事件循环的阻塞会被取消。这是唯一安全地从另外的线程调用的方法。(要在一个线程安全的方式去延迟一段时间调度回调函数,你可以使用ev.call_soon_threadsafe(ev.call_later,when,*args)。)但它在信号处理器中调用并不安全(因为它可以使用锁)。 add_signal_handler(sig,*args)。无论什么时候接收到信号 ``sigis , callback(*args)会被安排调用。返回一个能来取消信号回调函数的Handler。(取消返回的处理器回导致在下个信号到来的时候调用remove_signal_handler()。优先明确地调用remove_signal_handler()。)为相同的信号定义另外一个回到函数来替代之前的handler(每个信号只能激活一个handler)。sig参数必需是一个在信号模块里定义的有效的信号值。如果信号不能处理,这会抛出一个异常:如果它不是一个有效的信号或者如果它是一个不能捕获的信号(例如SIGKILL),会抛出ValueError。如果这个特别的事件循环实例不能处理信号(因为信号是每个处理器的全局变量,只有在主线程的事件循环才能处理这些信号),它会抛出RuntimeError。 remove_signal_handler(sig)。为信号sig移除handler,当有设置的时候。抛出和add_signal_handler()一样的异常(除了在不能不错的信号时返回False代替抛出RuntimeError)。如果handler移除成功,返回True,如果没有设置handler则返回False。 一些符合标准接口返回Future的方法: wrap_future(future)。 这里需要在PEP 3148 描述的Future (例如一个concurrent.futures.Future的实例) 同时返回一个兼容事件循环的Future (例如,一个tulip.Future实例)。 run_in_executor(executor,*args)。安排在一个执行器中调用callback(*args) (请看 PEP 3148)。返回的Future的成功的结果是调用的返回值。 这个方法等价于wrap_future(executor.submit(callback,*args))。 如果没有执行器,则会是也能够一个默认为5个线程的ThreadPoolExecutor。 set_default_executor(executor). 设置一个被run_in_executor()使用的默认执行器。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
