杭州杭州曙辰贸易有限公司司𣄃下产生的Oee是什么电气

&img src=&/v2-ae32e0a4e58d10efa4c42673acf2c390_b.png& data-rawwidth=&1920& data-rawheight=&937& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/v2-ae32e0a4e58d10efa4c42673acf2c390_r.png&&&p&本文将会讲述Python 3.5之后出现的async/await的使用方法,以及它们的一些使用目的,如果错误,欢迎指正。&/p&&p&昨天看到David Beazley在16年的一个演讲:&a href=&/?target=https%3A///watch%3Fv%3DE-1Y4kSsAFc& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Fear and Awaiting in Async&i class=&icon-external&&&/i&&/a&,给了我不少的感悟和启发,于是想梳理下自己的思路,所以有了以下这篇文章。&/p&&p&Python在3.5版本中引入了关于协程的语法糖async和await,关于协程的概念可以先看我在&a href=&/p/& class=&internal&&上一篇文章&/a&提到的内容。&/p&&p&看下Python中常见的几种函数形式:&/p&&p&
1. 普通函数&br&&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&function&/span&&span class=&p&&():&/span&
&span class=&k&&return&/span& &span class=&mi&&1&/span&
&/code&&/pre&&/div&
2. 生成器函数&br&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&generator&/span&&span class=&p&&():&/span&
&span class=&k&&yield&/span& &span class=&mi&&1&/span&
&/code&&/pre&&/div&&p&在3.5过后,我们可以使用async修饰将普通函数和生成器函数包装成异步函数和异步生成器。&/p&&p&
3. 异步函数(协程)&/p&&br&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&async_function&/span&&span class=&p&&():&/span&
&span class=&k&&return&/span& &span class=&mi&&1&/span&
&/code&&/pre&&/div&&p&
4. 异步生成器&/p&&br&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&async_generator&/span&&span class=&p&&():&/span&
&span class=&k&&yield&/span& &span class=&mi&&1&/span&
&/code&&/pre&&/div&&p&通过类型判断可以验证函数的类型&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&import&/span& &span class=&nn&&types&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&nb&&type&/span&&span class=&p&&(&/span&&span class=&n&&function&/span&&span class=&p&&)&/span& &span class=&ow&&is&/span& &span class=&n&&types&/span&&span class=&o&&.&/span&&span class=&n&&FunctionType&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&nb&&type&/span&&span class=&p&&(&/span&&span class=&n&&generator&/span&&span class=&p&&())&/span& &span class=&ow&&is&/span& &span class=&n&&types&/span&&span class=&o&&.&/span&&span class=&n&&GeneratorType&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&nb&&type&/span&&span class=&p&&(&/span&&span class=&n&&async_function&/span&&span class=&p&&())&/span& &span class=&ow&&is&/span& &span class=&n&&types&/span&&span class=&o&&.&/span&&span class=&n&&CoroutineType&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&nb&&type&/span&&span class=&p&&(&/span&&span class=&n&&async_generator&/span&&span class=&p&&())&/span& &span class=&ow&&is&/span& &span class=&n&&types&/span&&span class=&o&&.&/span&&span class=&n&&AsyncGeneratorType&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&直接调用异步函数不会返回结果,而是返回一个coroutine对象:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&async_function&/span&&span class=&p&&())&/span&
&span class=&c1&&# &coroutine object async_function at 0x102ff67d8&&/span&
&/code&&/pre&&/div&&p&协程需要通过其他方式来驱动,因此可以使用这个协程对象的send方法给协程发送一个值:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&async_function&/span&&span class=&p&&()&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&bp&&None&/span&&span class=&p&&))&/span&
&/code&&/pre&&/div&&p&不幸的是,如果通过上面的调用会抛出一个异常:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&ne&&StopIteration&/span&&span class=&p&&:&/span& &span class=&mi&&1&/span&
&/code&&/pre&&/div&&p&因为生成器/协程在正常返回退出时会抛出一个StopIteration异常,而原来的返回值会存放在StopIteration对象的value属性中,通过以下捕获可以获取协程真正的返回值:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&n&&async_function&/span&&span class=&p&&()&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&bp&&None&/span&&span class=&p&&)&/span&
&span class=&k&&except&/span& &span class=&ne&&StopIteration&/span& &span class=&k&&as&/span& &span class=&n&&e&/span&&span class=&p&&:&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&e&/span&&span class=&o&&.&/span&&span class=&n&&value&/span&&span class=&p&&)&/span&
&span class=&c1&&# 1&/span&
&/code&&/pre&&/div&&p&通过上面的方式来新建一个run函数来驱动协程函数:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&run&/span&&span class=&p&&(&/span&&span class=&n&&coroutine&/span&&span class=&p&&):&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&n&&coroutine&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&bp&&None&/span&&span class=&p&&)&/span&
&span class=&k&&except&/span& &span class=&ne&&StopIteration&/span& &span class=&k&&as&/span& &span class=&n&&e&/span&&span class=&p&&:&/span&
&span class=&k&&return&/span& &span class=&n&&e&/span&&span class=&o&&.&/span&&span class=&n&&value&/span&
&/code&&/pre&&/div&&p&在协程函数中,可以通过await语法来挂起自身的协程,并等待另一个协程完成直到返回结果:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&async_function&/span&&span class=&p&&():&/span&
&span class=&k&&return&/span& &span class=&mi&&1&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&await_coroutine&/span&&span class=&p&&():&/span&
&span class=&n&&result&/span& &span class=&o&&=&/span& &span class=&n&&await&/span& &span class=&n&&async_function&/span&&span class=&p&&()&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&result&/span&&span class=&p&&)&/span&
&span class=&n&&run&/span&&span class=&p&&(&/span&&span class=&n&&await_coroutine&/span&&span class=&p&&())&/span&
&span class=&c1&&# 1&/span&
&/code&&/pre&&/div&&p&要注意的是,await语法只能出现在通过async修饰的函数中,否则会报SyntaxError错误。&/p&&p&而且await后面的对象需要是一个Awaitable,或者实现了相关的协议。&/p&&p&查看Awaitable抽象类的代码,表明了只要一个类实现了__await__方法,那么通过它构造出来的实例就是一个Awaitable:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&Awaitable&/span&&span class=&p&&(&/span&&span class=&n&&metaclass&/span&&span class=&o&&=&/span&&span class=&n&&ABCMeta&/span&&span class=&p&&):&/span&
&span class=&n&&__slots__&/span& &span class=&o&&=&/span& &span class=&p&&()&/span&
&span class=&nd&&@abstractmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&__await__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&k&&yield&/span&
&span class=&nd&&@classmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&__subclasshook__&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&p&&,&/span& &span class=&n&&C&/span&&span class=&p&&):&/span&
&span class=&k&&if&/span& &span class=&n&&cls&/span& &span class=&ow&&is&/span& &span class=&n&&Awaitable&/span&&span class=&p&&:&/span&
&span class=&k&&return&/span& &span class=&n&&_check_methods&/span&&span class=&p&&(&/span&&span class=&n&&C&/span&&span class=&p&&,&/span& &span class=&s2&&&__await__&&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&bp&&NotImplemented&/span&
&/code&&/pre&&/div&&p&而且可以看到,Coroutine类也继承了Awaitable,而且实现了send,throw和close方法。所以await一个调用异步函数返回的协程对象是合法的。&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&Coroutine&/span&&span class=&p&&(&/span&&span class=&n&&Awaitable&/span&&span class=&p&&):&/span&
&span class=&n&&__slots__&/span& &span class=&o&&=&/span& &span class=&p&&()&/span&
&span class=&nd&&@abstractmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&send&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&value&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&nd&&@abstractmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&throw&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&typ&/span&&span class=&p&&,&/span& &span class=&n&&val&/span&&span class=&o&&=&/span&&span class=&bp&&None&/span&&span class=&p&&,&/span& &span class=&n&&tb&/span&&span class=&o&&=&/span&&span class=&bp&&None&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&k&&def&/span& &span class=&nf&&close&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&nd&&@classmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&__subclasshook__&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&p&&,&/span& &span class=&n&&C&/span&&span class=&p&&):&/span&
&span class=&k&&if&/span& &span class=&n&&cls&/span& &span class=&ow&&is&/span& &span class=&n&&Coroutine&/span&&span class=&p&&:&/span&
&span class=&k&&return&/span& &span class=&n&&_check_methods&/span&&span class=&p&&(&/span&&span class=&n&&C&/span&&span class=&p&&,&/span& &span class=&s1&&'__await__'&/span&&span class=&p&&,&/span& &span class=&s1&&'send'&/span&&span class=&p&&,&/span& &span class=&s1&&'throw'&/span&&span class=&p&&,&/span& &span class=&s1&&'close'&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&bp&&NotImplemented&/span&
&/code&&/pre&&/div&&p&接下来是异步生成器,来看一个例子:&/p&&p&假如我要到一家超市去购买土豆,而超市货架上的土豆数量是有限的:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&Potato&/span&&span class=&p&&:&/span&
&span class=&nd&&@classmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&make&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&p&&,&/span& &span class=&n&&num&/span&&span class=&p&&,&/span& &span class=&o&&*&/span&&span class=&n&&args&/span&&span class=&p&&,&/span& &span class=&o&&**&/span&&span class=&n&&kws&/span&&span class=&p&&):&/span&
&span class=&n&&potatos&/span& &span class=&o&&=&/span& &span class=&p&&[]&/span&
&span class=&k&&for&/span& &span class=&n&&i&/span& &span class=&ow&&in&/span& &span class=&nb&&range&/span&&span class=&p&&(&/span&&span class=&n&&num&/span&&span class=&p&&):&/span&
&span class=&n&&potatos&/span&&span class=&o&&.&/span&&span class=&n&&append&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&o&&.&/span&&span class=&n&&__new__&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&p&&,&/span& &span class=&o&&*&/span&&span class=&n&&args&/span&&span class=&p&&,&/span& &span class=&o&&**&/span&&span class=&n&&kws&/span&&span class=&p&&))&/span&
&span class=&k&&return&/span& &span class=&n&&potatos&/span&
&span class=&n&&all_potatos&/span& &span class=&o&&=&/span& &span class=&n&&Potato&/span&&span class=&o&&.&/span&&span class=&n&&make&/span&&span class=&p&&(&/span&&span class=&mi&&5&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&现在我想要买50个土豆,每次从货架上拿走一个土豆放到篮子:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&take_potatos&/span&&span class=&p&&(&/span&&span class=&n&&num&/span&&span class=&p&&):&/span&
&span class=&n&&count&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&k&&while&/span& &span class=&bp&&True&/span&&span class=&p&&:&/span&
&span class=&k&&if&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&all_potatos&/span&&span class=&p&&)&/span& &span class=&o&&==&/span& &span class=&mi&&0&/span&&span class=&p&&:&/span&
&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&o&&.&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&else&/span&&span class=&p&&:&/span&
&span class=&n&&potato&/span& &span class=&o&&=&/span& &span class=&n&&all_potatos&/span&&span class=&o&&.&/span&&span class=&n&&pop&/span&&span class=&p&&()&/span&
&span class=&k&&yield&/span& &span class=&n&&potato&/span&
&span class=&n&&count&/span& &span class=&o&&+=&/span& &span class=&mi&&1&/span&
&span class=&k&&if&/span& &span class=&n&&count&/span& &span class=&o&&==&/span& &span class=&n&&num&/span&&span class=&p&&:&/span&
&span class=&k&&break&/span&
&span class=&k&&def&/span& &span class=&nf&&buy_potatos&/span&&span class=&p&&():&/span&
&span class=&n&&bucket&/span& &span class=&o&&=&/span& &span class=&p&&[]&/span&
&span class=&k&&for&/span& &span class=&n&&p&/span& &span class=&ow&&in&/span& &span class=&n&&take_potatos&/span&&span class=&p&&(&/span&&span class=&mi&&50&/span&&span class=&p&&):&/span&
&span class=&n&&bucket&/span&&span class=&o&&.&/span&&span class=&n&&append&/span&&span class=&p&&(&/span&&span class=&n&&p&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&对应到代码中,就是迭代一个生成器的模型,显然,当货架上的土豆不够的时候,这时只能够死等,而且在上面例子中等多长时间都不会有结果(因为一切都是同步的),也许可以用多进程和多线程解决,而在现实生活中,更应该像是这样的:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&take_potatos&/span&&span class=&p&&(&/span&&span class=&n&&num&/span&&span class=&p&&):&/span&
&span class=&n&&count&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&k&&while&/span& &span class=&bp&&True&/span&&span class=&p&&:&/span&
&span class=&k&&if&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&all_potatos&/span&&span class=&p&&)&/span& &span class=&o&&==&/span& &span class=&mi&&0&/span&&span class=&p&&:&/span&
&span class=&n&&await&/span& &span class=&n&&ask_for_potato&/span&&span class=&p&&()&/span&
&span class=&n&&potato&/span& &span class=&o&&=&/span& &span class=&n&&all_potatos&/span&&span class=&o&&.&/span&&span class=&n&&pop&/span&&span class=&p&&()&/span&
&span class=&k&&yield&/span& &span class=&n&&potato&/span&
&span class=&n&&count&/span& &span class=&o&&+=&/span& &span class=&mi&&1&/span&
&span class=&k&&if&/span& &span class=&n&&count&/span& &span class=&o&&==&/span& &span class=&n&&num&/span&&span class=&p&&:&/span&
&span class=&k&&break&/span&
&/code&&/pre&&/div&&p&当货架上的土豆没有了之后,我可以询问超市请求需要更多的土豆,这时候需要等待一段时间直到生产者完成生产的过程:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&ask_for_potato&/span&&span class=&p&&():&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&n&&random&/span&&span class=&o&&.&/span&&span class=&n&&random&/span&&span class=&p&&())&/span&
&span class=&n&&all_potatos&/span&&span class=&o&&.&/span&&span class=&n&&extend&/span&&span class=&p&&(&/span&&span class=&n&&Potato&/span&&span class=&o&&.&/span&&span class=&n&&make&/span&&span class=&p&&(&/span&&span class=&n&&random&/span&&span class=&o&&.&/span&&span class=&n&&randint&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&,&/span& &span class=&mi&&10&/span&&span class=&p&&)))&/span&
&/code&&/pre&&/div&&p&当生产者完成和返回之后,这是便能从await挂起的地方继续往下跑,完成消费的过程。而这整一个过程,就是一个异步生成器迭代的流程:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&buy_potatos&/span&&span class=&p&&():&/span&
&span class=&n&&bucket&/span& &span class=&o&&=&/span& &span class=&p&&[]&/span&
&span class=&n&&async&/span& &span class=&k&&for&/span& &span class=&n&&p&/span& &span class=&ow&&in&/span& &span class=&n&&take_potatos&/span&&span class=&p&&(&/span&&span class=&mi&&50&/span&&span class=&p&&):&/span&
&span class=&n&&bucket&/span&&span class=&o&&.&/span&&span class=&n&&append&/span&&span class=&p&&(&/span&&span class=&n&&p&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&f&/span&&span class=&s1&&'Got potato {id(p)}...'&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&async for语法表示我们要后面迭代的是一个异步生成器。&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&main&/span&&span class=&p&&():&/span&
&span class=&kn&&import&/span& &span class=&nn&&asyncio&/span&
&span class=&n&&loop&/span& &span class=&o&&=&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&get_event_loop&/span&&span class=&p&&()&/span&
&span class=&n&&res&/span& &span class=&o&&=&/span& &span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&run_until_complete&/span&&span class=&p&&(&/span&&span class=&n&&buy_potatos&/span&&span class=&p&&())&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&用asyncio运行这段代码,结果是这样的:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&o&&...&/span&
&/code&&/pre&&/div&&p&既然是异步的,在请求之后不一定要死等,而是可以做其他事情。比如除了土豆,我还想买番茄,这时只需要在事件循环中再添加一个过程:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&main&/span&&span class=&p&&():&/span&
&span class=&kn&&import&/span& &span class=&nn&&asyncio&/span&
&span class=&n&&loop&/span& &span class=&o&&=&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&get_event_loop&/span&&span class=&p&&()&/span&
&span class=&n&&res&/span& &span class=&o&&=&/span& &span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&run_until_complete&/span&&span class=&p&&(&/span&&span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&wait&/span&&span class=&p&&([&/span&&span class=&n&&buy_potatos&/span&&span class=&p&&(),&/span& &span class=&n&&buy_tomatos&/span&&span class=&p&&()]))&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&再来运行这段代码:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&tomato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&tomato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&tomato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&tomato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&potato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&n&&Got&/span& &span class=&n&&tomato&/span& &span class=&mf&&.&/span&&span class=&o&&..&/span&
&span class=&o&&...&/span&
&/code&&/pre&&/div&&p&看下AsyncGenerator的定义,它需要实现__aiter__和__anext__两个核心方法,以及asend,athrow,aclose方法。&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&AsyncGenerator&/span&&span class=&p&&(&/span&&span class=&n&&AsyncIterator&/span&&span class=&p&&):&/span&
&span class=&n&&__slots__&/span& &span class=&o&&=&/span& &span class=&p&&()&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&__anext__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&nd&&@abstractmethod&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&asend&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&value&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&nd&&@abstractmethod&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&athrow&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&typ&/span&&span class=&p&&,&/span& &span class=&n&&val&/span&&span class=&o&&=&/span&&span class=&bp&&None&/span&&span class=&p&&,&/span& &span class=&n&&tb&/span&&span class=&o&&=&/span&&span class=&bp&&None&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&aclose&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&nd&&@classmethod&/span&
&span class=&k&&def&/span& &span class=&nf&&__subclasshook__&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&p&&,&/span& &span class=&n&&C&/span&&span class=&p&&):&/span&
&span class=&k&&if&/span& &span class=&n&&cls&/span& &span class=&ow&&is&/span& &span class=&n&&AsyncGenerator&/span&&span class=&p&&:&/span&
&span class=&k&&return&/span& &span class=&n&&_check_methods&/span&&span class=&p&&(&/span&&span class=&n&&C&/span&&span class=&p&&,&/span& &span class=&s1&&'__aiter__'&/span&&span class=&p&&,&/span& &span class=&s1&&'__anext__'&/span&&span class=&p&&,&/span&
&span class=&s1&&'asend'&/span&&span class=&p&&,&/span& &span class=&s1&&'athrow'&/span&&span class=&p&&,&/span& &span class=&s1&&'aclose'&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&bp&&NotImplemented&/span&
&/code&&/pre&&/div&&p&异步生成器是在3.6之后才有的特性,同样的还有异步推导表达式,因此在上面的例子中,也可以写成这样:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&bucket&/span& &span class=&o&&=&/span& &span class=&p&&[&/span&&span class=&n&&p&/span& &span class=&n&&async&/span& &span class=&k&&for&/span& &span class=&n&&p&/span& &span class=&ow&&in&/span& &span class=&n&&take_potatos&/span&&span class=&p&&(&/span&&span class=&mi&&50&/span&&span class=&p&&)]&/span&
&/code&&/pre&&/div&&p&类似的,还有await表达式:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&result&/span& &span class=&o&&=&/span& &span class=&p&&[&/span&&span class=&n&&await&/span& &span class=&n&&fun&/span&&span class=&p&&()&/span& &span class=&k&&for&/span& &span class=&n&&fun&/span& &span class=&ow&&in&/span& &span class=&n&&funcs&/span& &span class=&k&&if&/span& &span class=&n&&await&/span& &span class=&n&&condition&/span&&span class=&p&&()]&/span&
&/code&&/pre&&/div&&p&除了函数之外,类实例的普通方法也能用async语法修饰:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&ThreeTwoOne&/span&&span class=&p&&:&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&begin&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&mi&&3&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&game&/span&&span class=&p&&():&/span&
&span class=&n&&t&/span& &span class=&o&&=&/span& &span class=&n&&ThreeTwoOne&/span&&span class=&p&&()&/span&
&span class=&n&&await&/span& &span class=&n&&t&/span&&span class=&o&&.&/span&&span class=&n&&begin&/span&&span class=&p&&()&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'start'&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&实例方法的调用同样是返回一个coroutine:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&function&/span& &span class=&o&&=&/span& &span class=&n&&ThreeTwoOne&/span&&span class=&o&&.&/span&&span class=&n&&begin&/span&
&span class=&n&&method&/span& &span class=&o&&=&/span& &span class=&n&&function&/span&&span class=&o&&.&/span&&span class=&n&&__get__&/span&&span class=&p&&(&/span&&span class=&n&&ThreeTwoOne&/span&&span class=&p&&,&/span& &span class=&n&&ThreeTwoOne&/span&&span class=&p&&())&/span&
&span class=&kn&&import&/span& &span class=&nn&&inspect&/span&
&span class=&k&&assert&/span& &span class=&n&&inspect&/span&&span class=&o&&.&/span&&span class=&n&&isfunction&/span&&span class=&p&&(&/span&&span class=&n&&function&/span&&span class=&p&&)&/span&
&span class=&k&&assert&/span& &span class=&n&&inspect&/span&&span class=&o&&.&/span&&span class=&n&&ismethod&/span&&span class=&p&&(&/span&&span class=&n&&method&/span&&span class=&p&&)&/span&
&span class=&k&&assert&/span& &span class=&n&&inspect&/span&&span class=&o&&.&/span&&span class=&n&&iscoroutine&/span&&span class=&p&&(&/span&&span class=&n&&method&/span&&span class=&p&&())&/span&
&/code&&/pre&&/div&&p&同理还有类方法:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&ThreeTwoOne&/span&&span class=&p&&:&/span&
&span class=&nd&&@classmethod&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&begin&/span&&span class=&p&&(&/span&&span class=&n&&cls&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&mi&&3&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&game&/span&&span class=&p&&():&/span&
&span class=&n&&await&/span& &span class=&n&&ThreeTwoOne&/span&&span class=&o&&.&/span&&span class=&n&&begin&/span&&span class=&p&&()&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'start'&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&根据PEP 492中,async也可以应用到上下文管理器中,__aenter__和__aexit__需要返回一个Awaitable:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&GameContext&/span&&span class=&p&&:&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&__aenter__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game loading...'&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&__aexit__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&exc_type&/span&&span class=&p&&,&/span& &span class=&n&&exc&/span&&span class=&p&&,&/span& &span class=&n&&tb&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game exit...'&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&game&/span&&span class=&p&&():&/span&
&span class=&n&&async&/span& &span class=&k&&with&/span& &span class=&n&&GameContext&/span&&span class=&p&&():&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game start...'&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&在3.7版本,contextlib中会新增一个asynccontextmanager装饰器来包装一个实现异步协议的上下文管理器:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&from&/span& &span class=&nn&&contextlib&/span& &span class=&kn&&import&/span& &span class=&n&&asynccontextmanager&/span&
&span class=&nd&&@asynccontextmanager&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&get_connection&/span&&span class=&p&&():&/span&
&span class=&n&&conn&/span& &span class=&o&&=&/span& &span class=&n&&await&/span& &span class=&n&&acquire_db_connection&/span&&span class=&p&&()&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&k&&yield&/span&
&span class=&k&&finally&/span&&span class=&p&&:&/span&
&span class=&n&&await&/span& &span class=&n&&release_db_connection&/span&&span class=&p&&(&/span&&span class=&n&&conn&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&async修饰符也能用在__call__方法上:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&GameContext&/span&&span class=&p&&:&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&__aenter__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_started&/span& &span class=&o&&=&/span& &span class=&n&&time&/span&&span class=&p&&()&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game loading...'&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&bp&&self&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&__aexit__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&exc_type&/span&&span class=&p&&,&/span& &span class=&n&&exc&/span&&span class=&p&&,&/span& &span class=&n&&tb&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game exit...'&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&__call__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&o&&*&/span&&span class=&n&&args&/span&&span class=&p&&,&/span& &span class=&o&&**&/span&&span class=&n&&kws&/span&&span class=&p&&):&/span&
&span class=&k&&if&/span& &span class=&n&&args&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span& &span class=&o&&==&/span& &span class=&s1&&'time'&/span&&span class=&p&&:&/span&
&span class=&k&&return&/span& &span class=&n&&time&/span&&span class=&p&&()&/span& &span class=&o&&-&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_started&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&game&/span&&span class=&p&&():&/span&
&span class=&n&&async&/span& &span class=&k&&with&/span& &span class=&n&&GameContext&/span&&span class=&p&&()&/span& &span class=&k&&as&/span& &span class=&n&&ctx&/span&&span class=&p&&:&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game start...'&/span&&span class=&p&&)&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'game time: '&/span&&span class=&p&&,&/span& &span class=&n&&await&/span& &span class=&n&&ctx&/span&&span class=&p&&(&/span&&span class=&s1&&'time'&/span&&span class=&p&&))&/span&
&/code&&/pre&&/div&&p&&strong&await和yield from&/strong&&/p&&p&Python3.3的yield from语法可以把生成器的操作委托给另一个生成器,生成器的调用方可以直接与子生成器进行通信:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&sub_gen&/span&&span class=&p&&():&/span&
&span class=&k&&yield&/span& &span class=&mi&&1&/span&
&span class=&k&&yield&/span& &span class=&mi&&2&/span&
&span class=&k&&yield&/span& &span class=&mi&&3&/span&
&span class=&k&&def&/span& &span class=&nf&&gen&/span&&span class=&p&&():&/span&
&span class=&k&&return&/span& &span class=&p&&(&/span&&span class=&k&&yield from&/span& &span class=&n&&sub_gen&/span&&span class=&p&&())&/span&
&span class=&k&&def&/span& &span class=&nf&&main&/span&&span class=&p&&():&/span&
&span class=&k&&for&/span& &span class=&n&&val&/span& &span class=&ow&&in&/span& &span class=&n&&gen&/span&&span class=&p&&():&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&val&/span&&span class=&p&&)&/span&
&span class=&c1&&# 1&/span&
&span class=&c1&&# 2&/span&
&span class=&c1&&# 3&/span&
&/code&&/pre&&/div&&p&利用这一特性,使用yield from能够编写出类似协程效果的函数调用,在3.5之前,asyncio正是使用@asyncio.coroutine和yield from语法来创建协程:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&c1&&# https://docs.python.org/3.4/library/asyncio-task.html&/span&
&span class=&kn&&import&/span& &span class=&nn&&asyncio&/span&
&span class=&nd&&@asyncio.coroutine&/span&
&span class=&k&&def&/span& &span class=&nf&&compute&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s2&&&Compute &/span&&span class=&si&&%s&/span&&span class=&s2&& + &/span&&span class=&si&&%s&/span&&span class=&s2&& ...&&/span& &span class=&o&&%&/span& &span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&))&/span&
&span class=&k&&yield from&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mf&&1.0&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&n&&x&/span& &span class=&o&&+&/span& &span class=&n&&y&/span&
&span class=&nd&&@asyncio.coroutine&/span&
&span class=&k&&def&/span& &span class=&nf&&print_sum&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&):&/span&
&span class=&n&&result&/span& &span class=&o&&=&/span& &span class=&k&&yield from&/span& &span class=&n&&compute&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&si&&%s&/span&&span class=&s2&& + &/span&&span class=&si&&%s&/span&&span class=&s2&& = &/span&&span class=&si&&%s&/span&&span class=&s2&&&&/span& &span class=&o&&%&/span& &span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&,&/span& &span class=&n&&result&/span&&span class=&p&&))&/span&
&span class=&n&&loop&/span& &span class=&o&&=&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&get_event_loop&/span&&span class=&p&&()&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&run_until_complete&/span&&span class=&p&&(&/span&&span class=&n&&print_sum&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&,&/span& &span class=&mi&&2&/span&&span class=&p&&))&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&然而,用yield from容易在表示协程和生成器中混淆,没有良好的语义性,所以在Python 3.5推出了更新的async/await表达式来作为协程的语法。&/p&&p&因此类似以下的调用是等价的:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&n&&async&/span& &span class=&k&&with&/span& &span class=&n&&lock&/span&&span class=&p&&:&/span&
&span class=&o&&...&/span&
&span class=&k&&with&/span& &span class=&p&&(&/span&&span class=&k&&yield from&/span& &span class=&n&&lock&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&c1&&######################&/span&
&span class=&k&&def&/span& &span class=&nf&&main&/span&&span class=&p&&():&/span&
&span class=&k&&return&/span& &span class=&p&&(&/span&&span class=&k&&yield from&/span& &span class=&n&&coro&/span&&span class=&p&&())&/span&
&span class=&k&&def&/span& &span class=&nf&&main&/span&&span class=&p&&():&/span&
&span class=&k&&return&/span& &span class=&p&&(&/span&&span class=&n&&await&/span& &span class=&n&&coro&/span&&span class=&p&&())&/span&
&/code&&/pre&&/div&&p&那么,怎么把生成器包装为一个协程对象呢?这时候可以用到types包中的coroutine装饰器(如果使用asyncio做驱动的话,那么也可以使用asyncio的coroutine装饰器),@types.coroutine装饰器会将一个生成器函数包装为协程对象:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&import&/span& &span class=&nn&&asyncio&/span&
&span class=&kn&&import&/span& &span class=&nn&&types&/span&
&span class=&nd&&@types.coroutine&/span&
&span class=&k&&def&/span& &span class=&nf&&compute&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s2&&&Compute &/span&&span class=&si&&%s&/span&&span class=&s2&& + &/span&&span class=&si&&%s&/span&&span class=&s2&& ...&&/span& &span class=&o&&%&/span& &span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&))&/span&
&span class=&k&&yield from&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mf&&1.0&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&n&&x&/span& &span class=&o&&+&/span& &span class=&n&&y&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&print_sum&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&):&/span&
&span class=&n&&result&/span& &span class=&o&&=&/span& &span class=&n&&await&/span& &span class=&n&&compute&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s2&&&&/span&&span class=&si&&%s&/span&&span class=&s2&& + &/span&&span class=&si&&%s&/span&&span class=&s2&& = &/span&&span class=&si&&%s&/span&&span class=&s2&&&&/span& &span class=&o&&%&/span& &span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&n&&y&/span&&span class=&p&&,&/span& &span class=&n&&result&/span&&span class=&p&&))&/span&
&span class=&n&&loop&/span& &span class=&o&&=&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&get_event_loop&/span&&span class=&p&&()&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&run_until_complete&/span&&span class=&p&&(&/span&&span class=&n&&print_sum&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&,&/span& &span class=&mi&&2&/span&&span class=&p&&))&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&尽管两个函数分别使用了新旧语法,但他们都是协程对象,也分别称作&em&native coroutine&/em&以及&em&generator-based coroutine&/em&,因此不用担心语法问题。&/p&&p&下面观察一个asyncio中Future的例子:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&import&/span& &span class=&nn&&asyncio&/span&
&span class=&n&&future&/span& &span class=&o&&=&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&Future&/span&&span class=&p&&()&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&coro1&/span&&span class=&p&&():&/span&
&span class=&n&&await&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&future&/span&&span class=&o&&.&/span&&span class=&n&&set_result&/span&&span class=&p&&(&/span&&span class=&s1&&'data'&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&coro2&/span&&span class=&p&&():&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&n&&await&/span& &span class=&n&&future&/span&&span class=&p&&)&/span&
&span class=&n&&loop&/span& &span class=&o&&=&/span& &span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&get_event_loop&/span&&span class=&p&&()&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&run_until_complete&/span&&span class=&p&&(&/span&&span class=&n&&asyncio&/span&&span class=&o&&.&/span&&span class=&n&&wait&/span&&span class=&p&&([&/span&
&span class=&n&&coro1&/span&&span class=&p&&(),&/span&
&span class=&n&&coro2&/span&&span class=&p&&()&/span&
&span class=&p&&]))&/span&
&span class=&n&&loop&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&两个协程在在事件循环中,协程coro1在执行第一句后挂起自身切到asyncio.sleep,而协程coro2一直等待future的结果,让出事件循环,计时器结束后coro1执行了第二句设置了future的值,被挂起的coro2恢复执行,打印出future的结果'data'。&/p&&p&future可以被await证明了future对象是一个Awaitable,进入Future类的源码可以看到有一段代码显示了future实现了__await__协议:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&Future&/span&&span class=&p&&:&/span&
&span class=&o&&...&/span&
&span class=&k&&def&/span& &span class=&nf&&__iter__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&done&/span&&span class=&p&&():&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_asyncio_future_blocking&/span& &span class=&o&&=&/span& &span class=&bp&&True&/span&
&span class=&k&&yield&/span& &span class=&bp&&self&/span&
&span class=&c1&&# This tells Task to wait for completion.&/span&
&span class=&k&&assert&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&done&/span&&span class=&p&&(),&/span& &span class=&s2&&&yield from wasn't used with future&&/span&
&span class=&k&&return&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&result&/span&&span class=&p&&()&/span&
&span class=&c1&&# May raise too.&/span&
&span class=&k&&if&/span& &span class=&n&&compat&/span&&span class=&o&&.&/span&&span class=&n&&PY35&/span&&span class=&p&&:&/span&
&span class=&n&&__await__&/span& &span class=&o&&=&/span& &span class=&n&&__iter__&/span& &span class=&c1&&# make compatible with 'await' expression&/span&
&/code&&/pre&&/div&&p&当执行&strong&await future&/strong&这行代码时,future中的这段代码就会被执行,首先future检查它自身是否已经完成,如果没有完成,挂起自身,告知当前的Task(任务)等待future完成。&/p&&p&当future执行set_result方法时,会触发以下的代码,设置结果,标记future已经完成:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&set_result&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&,&/span& &span class=&n&&result&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&k&&if&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_state&/span& &span class=&o&&!=&/span& &span class=&n&&_PENDING&/span&&span class=&p&&:&/span&
&span class=&k&&raise&/span& &span class=&n&&InvalidStateError&/span&&span class=&p&&(&/span&&span class=&s1&&'{}: {!r}'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_state&/span&&span class=&p&&,&/span& &span class=&bp&&self&/span&&span class=&p&&))&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_result&/span& &span class=&o&&=&/span& &span class=&n&&result&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_state&/span& &span class=&o&&=&/span& &span class=&n&&_FINISHED&/span&
&span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&_schedule_callbacks&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&最后future会调度自身的回调函数,触发Task._step()告知Task驱动future从之前挂起的点恢复执行,不难看出,future会执行下面的代码:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&Future&/span&&span class=&p&&:&/span&
&span class=&o&&...&/span&
&span class=&k&&def&/span& &span class=&nf&&__iter__&/span&&span class=&p&&(&/span&&span class=&bp&&self&/span&&span class=&p&&):&/span&
&span class=&o&&...&/span&
&span class=&k&&assert&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&done&/span&&span class=&p&&(),&/span& &span class=&s2&&&yield from wasn't used with future&&/span&
&span class=&k&&return&/span& &span class=&bp&&self&/span&&span class=&o&&.&/span&&span class=&n&&result&/span&&span class=&p&&()&/span&
&span class=&c1&&# May raise too.&/span&
&/code&&/pre&&/div&&p&最终返回结果给调用方。&/p&&p&前面讲了那么多关于asyncio的例子,那么除了asyncio,就没有其他协程库了吗?asyncio作为python的标准库,自然受到很多青睐,但它有时候还是显得太重量了,尤其是提供了许多复杂的轮子和协议,不便于使用。&/p&&p&你可以理解为,asyncio是使用async/await语法开发的协程库,而不是有asyncio才能用async/await,除了asyncio之外,curio和trio是更加轻量级的替代物,而且也更容易使用。&/p&&p&curio的作者是David Beazley,下面是使用curio创建tcp server的例子,据说这是dabeaz理想中的一个异步服务器的样子:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&from&/span& &span class=&nn&&curio&/span& &span class=&kn&&import&/span& &span class=&n&&run&/span&&span class=&p&&,&/span& &span class=&n&&spawn&/span&
&span class=&kn&&from&/span& &span class=&nn&&curio.socket&/span& &span class=&kn&&import&/span& &span class=&o&&*&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&echo_server&/span&&span class=&p&&(&/span&&span class=&n&&address&/span&&span class=&p&&):&/span&
&span class=&n&&sock&/span& &span class=&o&&=&/span& &span class=&n&&socket&/span&&span class=&p&&(&/span&&span class=&n&&AF_INET&/span&&span class=&p&&,&/span& &span class=&n&&SOCK_STREAM&/span&&span class=&p&&)&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&setsockopt&/span&&span class=&p&&(&/span&&span class=&n&&SOL_SOCKET&/span&&span class=&p&&,&/span& &span class=&n&&SO_REUSEADDR&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&bind&/span&&span class=&p&&(&/span&&span class=&n&&address&/span&&span class=&p&&)&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&listen&/span&&span class=&p&&(&/span&&span class=&mi&&5&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'Server listening at'&/span&&span class=&p&&,&/span& &span class=&n&&address&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&with&/span& &span class=&n&&sock&/span&&span class=&p&&:&/span&
&span class=&k&&while&/span& &span class=&bp&&True&/span&&span class=&p&&:&/span&
&span class=&n&&client&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span& &span class=&o&&=&/span& &span class=&n&&await&/span& &span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&accept&/span&&span class=&p&&()&/span&
&span class=&n&&await&/span& &span class=&n&&spawn&/span&&span class=&p&&(&/span&&span class=&n&&echo_client&/span&&span class=&p&&,&/span& &span class=&n&&client&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&def&/span& &span class=&nf&&echo_client&/span&&span class=&p&&(&/span&&span class=&n&&client&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'Connection from'&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span&&span class=&p&&)&/span&
&span class=&n&&async&/span& &span class=&k&&with&/span& &span class=&n&&client&/span&&span class=&p&&:&/span&
&span class=&k&&while&/span& &span class=&bp&&True&/span&&span class=&p&&:&/span&
&span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&n&&await&/span& &span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&recv&/span&&span class=&p&&(&/span&&span class=&mi&&100000&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&n&&data&/span&&span class=&p&&:&/span&
&span class=&k&&break&/span&
&span class=&n&&await&/span& &span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&sendall&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&k&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'Connection closed'&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&n&&__name__&/span& &span class=&o&&==&/span& &span class=&s1&&'__main__'&/span&&span class=&p&&:&/span&
&span class=&n&&run&/span&&span class=&p&&(&/span&&span class=&n&&echo_server&/span&&span class=&p&&,&/span& &span class=&p&&(&/span&&span class=&s1&&''&/span&&span class=&p&&,&/span&&span class=&mi&&25000&/span&&span class=&p&&))&/span&
&/code&&/pre&&/div&&p&无论是asyncio还是curio,或者是其他异步协程库,在背后往往都会借助于IO的事件循环来实现异步,下面用几十行代码来展示一个简陋的基于事件驱动的echo服务器:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&from&/span& &span class=&nn&&socket&/span& &span class=&kn&&import&/span& &span class=&n&&socket&/span&&span class=&p&&,&/span& &span class=&n&&AF_INET&/span&&span class=&p&&,&/span& &span class=&n&&SOCK_STREAM&/span&&span class=&p&&,&/span& &span class=&n&&SOL_SOCKET&/span&&span class=&p&&,&/span& &span class=&n&&SO_REUSEADDR&/span&
&span class=&kn&&from&/span& &span class=&nn&&selectors&/span& &span class=&kn&&import&/span& &span class=&n&&DefaultSelector&/span&&span class=&p&&,&/span& &span class=&n&&EVENT_READ&/span&
&span class=&n&&selector&/span& &span class=&o&&=&/span& &span class=&n&&DefaultSelector&/span&&span class=&p&&()&/span&
&span class=&n&&pool&/span& &span class=&o&&=&/span& &span class=&p&&{}&/span&
&span class=&k&&def&/span& &span class=&nf&&request&/span&&span class=&p&&(&/span&&span class=&n&&client_socket&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span&&span class=&p&&):&/span&
&span class=&n&&client_socket&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span& &span class=&o&&=&/span& &span class=&n&&client_socket&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span&
&span class=&k&&def&/span& &span class=&nf&&handle_request&/span&&span class=&p&&(&/span&&span class=&n&&key&/span&&span class=&p&&,&/span& &span class=&n&&mask&/span&&span class=&p&&):&/span&
&span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&n&&client_socket&/span&&span class=&o&&.&/span&&span class=&n&&recv&/span&&span class=&p&&(&/span&&span class=&mi&&100000&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&n&&data&/span&&span class=&p&&:&/span&
&span class=&n&&client_socket&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&span class=&n&&selector&/span&&span class=&o&&.&/span&&span class=&n&&unregister&/span&&span class=&p&&(&/span&&span class=&n&&client_socket&/span&&span class=&p&&)&/span&
&span class=&k&&del&/span& &span class=&n&&pool&/span&&span class=&p&&[&/span&&span class=&n&&addr&/span&&span class=&p&&]&/span&
&span class=&k&&else&/span&&span class=&p&&:&/span&
&span class=&n&&client_socket&/span&&span class=&o&&.&/span&&span class=&n&&sendall&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&n&&handle_request&/span&
&span class=&k&&def&/span& &span class=&nf&&recv_client&/span&&span class=&p&&(&/span&&span class=&n&&key&/span&&span class=&p&&,&/span& &span class=&n&&mask&/span&&span class=&p&&):&/span&
&span class=&n&&sock&/span& &span class=&o&&=&/span& &span class=&n&&key&/span&&span class=&o&&.&/span&&span class=&n&&fileobj&/span&
&span class=&n&&client_socket&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span& &span class=&o&&=&/span& &span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&accept&/span&&span class=&p&&()&/span&
&span class=&n&&req&/span& &span class=&o&&=&/span& &span class=&n&&request&/span&&span class=&p&&(&/span&&span class=&n&&client_socket&/span&&span class=&p&&,&/span& &span class=&n&&addr&/span&&span class=&p&&)&/span&
&span class=&n&&pool&/span&&span class=&p&&[&/span&&span class=&n&&addr&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&n&&req&/span&
&span class=&n&&selector&/span&&span class=&o&&.&/span&&span class=&n&&register&/span&&span class=&p&&(&/span&&span class=&n&&client_socket&/span&&span class=&p&&,&/span& &span class=&n&&EVENT_READ&/span&&span class=&p&&,&/span& &span class=&n&&req&/span&&span class=&p&&)&/span&
&span class=&k&&def&/span& &span class=&nf&&echo_server&/span&&span class=&p&&(&/span&&span class=&n&&address&/span&&span class=&p&&):&/span&
&span class=&n&&sock&/span& &span class=&o&&=&/span& &span class=&n&&socket&/span&&span class=&p&&(&/span&&span class=&n&&AF_INET&/span&&span class=&p&&,&/span& &span class=&n&&SOCK_STREAM&/span&&span class=&p&&)&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&setsockopt&/span&&span class=&p&&(&/span&&span class=&n&&SOL_SOCKET&/span&&span class=&p&&,&/span& &span class=&n&&SO_REUSEADDR&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&bind&/span&&span class=&p&&(&/span&&span class=&n&&address&/span&&span class=&p&&)&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&listen&/span&&span class=&p&&(&/span&&span class=&mi&&5&/span&&span class=&p&&)&/span&
&span class=&n&&selector&/span&&span class=&o&&.&/span&&span class=&n&&register&/span&&span class=&p&&(&/span&&span class=&n&&sock&/span&&span class=&p&&,&/span& &span class=&n&&EVENT_READ&/span&&span class=&p&&,&/span& &span class=&n&&recv_client&/span&&span class=&p&&)&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&k&&while&/span& &span class=&bp&&True&/span&&span class=&p&&:&/span&
&span class=&n&&events&/span& &span class=&o&&=&/span& &span class=&n&&selector&/span&&span class=&o&&.&/span&&span class=&n&&select&/span&&span class=&p&&()&/span&
&span class=&k&&for&/span& &span class=&n&&key&/span&&span class=&p&&,&/span& &span class=&n&&mask&/span& &span class=&ow&&in&/span& &span class=&n&&events&/span&&span class=&p&&:&/span&
&span class=&n&&callback&/span& &span class=&o&&=&/span& &span class=&n&&key&/span&&span class=&o&&.&/span&&span class=&n&&data&/span&
&span class=&n&&callback&/span&&span class=&p&&(&/span&&span class=&n&&key&/span&&span class=&p&&,&/span& &span class=&n&&mask&/span&&span class=&p&&)&/span&
&span class=&k&&except&/span& &span class=&ne&&KeyboardInterrupt&/span&&span class=&p&&:&/span&
&span class=&n&&sock&/span&&span class=&o&&.&/span&&span class=&n&&close&/span&&span class=&p&&()&/span&
&span class=&k&&if&/span& &span class=&n&&__name__&/span& &span class=&o&&==&/span& &span class=&s1&&'__main__'&/span&&span class=&p&&:&/span&
&span class=&n&&echo_server&/span&&span class=&p&&((&/span&&span class=&s1&&''&/span&&span class=&p&&,&/span&&span class=&mi&&25000&/span&&span class=&p&&))&/span&
&/code&&/pre&&/div&&p&验证一下:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# terminal 1&/span&
$ nc localhost 25000
hello world
hello world
&span class=&c1&&# terminal 2&/span&
$ nc localhost 25000
hello world
hello world
&/code&&/pre&&/div&&p&现在知道,完成异步的代码不一定要用async/await,使用了async/await的代码也不一定能做到异步,async/await是协程的语法糖,使协程之间的调用变得更加清晰,使用async修饰的函数调用时会返回一个协程对象,await只能放在async修饰的函数里面使用,await后面必须要跟着一个协程对象或Awaitable,await的目的是等待协程控制流的返回,而实现暂停并挂起函数的操作是yield。&/p&&p&个人认为,async/await以及协程是Python未来实现异步编程的趋势,我们将会在更多的地方看到他们的身影,例如协程库的curio和trio,web框架的sanic,数据库驱动的asyncpg等等...在Python 3主导的今天,作为开发者,应该及时拥抱和适应新的变化,而基于async/await的协程凭借良好的可读性和易用性日渐登上舞台,看到这里,你还不赶紧上车?&/p&&br&&p&参考:&/p&&a href=&/?target=https%3A//www.python.org/dev/peps/pep-0492/%23new-standard-library-functions& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PEP 492&i class=&icon-external&&&/i&&/a&&a href=&/?target=https%3A//www.python.org/dev/peps/pep-0525/%23asynchronous-generators& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PEP 525&i class=&icon-external&&&/i&&/a&
本文将会讲述Python 3.5之后出现的async/await的使用方法,以及它们的一些使用目的,如果错误,欢迎指正。昨天看到David Beazley在16年的一个演讲:,给了我不少的感悟和启发,于是想梳理下自己的思路,所以有了以下这篇文章。Py…
&p&&b&本文为万门机构号资源整理系列的13号文。&/b& &/p&&p&&b&这一次,给大家带来9个行业报告相关的网站。&/b&&/p&&br&&p&&b&13.1 199IT互联网数据中心:&a href=&///?target=http%3A///& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-0f25b318f5f55ce5b9d15bc373cd67cf_b.png& data-rawwidth=&600& data-rawheight=&287& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-0f25b318f5f55ce5b9d15bc373cd67cf_r.png&&&br&&p&&b&13.2 艾瑞网:&a href=&///?target=http%3A///& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-d1760467dfe2feef2abb3_b.png& data-rawwidth=&600& data-rawheight=&311& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-d1760467dfe2feef2abb3_r.png&&&br&&p&&b&13.3 中国互联网络信息中心:&a href=&///?target=http%3A//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-e177e882fba1bafceafc88_b.png& data-rawwidth=&600& data-rawheight=&338& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-e177e882fba1bafceafc88_r.png&&&br&&p&&b&13.4 艾媒网:&a href=&///?target=http%3A//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-35ebb091ed0_b.png& data-rawwidth=&600& data-rawheight=&279& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-35ebb091ed0_r.png&&&br&&p&&b&13.5 艺恩网:&a href=&///?target=http%3A///report/f/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&/report/f/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-6dd9cd5d82de86206b5caf02e28d8c9d_b.png& data-rawwidth=&600& data-rawheight=&346& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-6dd9cd5d82de86206b5caf02e28d8c9d_r.png&&&br&&p&&b&13.6 易观智库:&a href=&///?target=https%3A//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-1d0b8afbad5aa68cbce8_b.png& data-rawwidth=&600& data-rawheight=&313& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-1d0b8afbad5aa68cbce8_r.png&&&br&&p&&b&13.7 腾讯大数据:&a href=&///?target=http%3A///reports& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&/reports&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-a9d130fb909cabfc915a9_b.png& data-rawwidth=&600& data-rawheight=&300& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-a9d130fb909cabfc915a9_r.png&&&br&&p&&b&13.8 阿里研究院:&a href=&///?target=http%3A//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-dd5a52ec042daa_b.png& data-rawwidth=&600& data-rawheight=&308& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-dd5a52ec042daa_r.png&&&br&&p&&b&13.9 360研究报告:&a href=&///?target=http%3A///report/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&/report/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&/b&&/p&&img src=&/v2-3fbeeb1baf3f5e4f216a07_b.png& data-rawwidth=&600& data-rawheight=&340& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-3fbeeb1baf3f5e4f216a07_r.png&&&br&&p&&b&本文从属于这篇小合集:&a href=&/p/& class=&internal&&【资源整理5-13号】简历,PDF转换,录

我要回帖

更多关于 杭州搏耐贸易有限公司 的文章

 

随机推荐