Python 协同程序的收益与任务的收益
Guido van Rossum在2014年关于郁金香/Asyncio的演讲中: 任务与合作计划的对比Python 协同程序的收益与任务的收益,python,python-3.x,asynchronous,concurrency,python-asyncio,Python,Python 3.x,Asynchronous,Concurrency,Python Asyncio,Guido van Rossum在2014年关于郁金香/Asyncio的演讲中: 任务与合作计划的对比 比较: res=某个合作项目的收益率(…) res=任务的收益率(某些协同程序(…) 任务可以在不等待的情况下取得进展 在你等待其他东西的时候记日志 i、 e.来自 我完全没有抓住要点 在我看来,两种结构都是相同的: 在裸协同路由的情况下-它得到调度,因此无论如何都会创建任务,因为调度器与任务一起运行,所以协同路由调用方协同路由将被挂起,直到被调用方完成,然后可以自由地继续执行
- 比较:
- res=某个合作项目的收益率(…)
- res=任务的收益率(某些协同程序(…)
- 任务可以在不等待的情况下取得进展
- 在你等待其他东西的时候记日志
- i、 e.来自
- 在你等待其他东西的时候记日志
任务
的情况下,仍然会安排新任务,调用方协同路由等待其完成
<> P>在这两种情况下代码执行的方式有什么不同,开发者在实践中应该考虑哪些影响?
p、 s.非常感谢权威来源(GvR、PEP、文档、核心开发人员注释)的链接。对于调用方的共同例程,
coroutine()的收益感觉就像一个函数调用(即,当coroutine()完成时,它将再次获得控制权)
yield from Task(coroutine())
另一方面,感觉更像是创建一个新线程Task()
几乎立即返回,并且很可能在coroutine()
完成之前调用方获得了控制权
f()
和th=threading.Thread(target=f,args=())之间的差异;th.start();join()是显而易见的,对吗?使用asyncio.Task(coro())
的意义在于,您不想显式地等待coro
,但希望在等待其他任务时在后台执行coro
。这就是Guido幻灯片的意思
[A] 任务
可以在不等待的情况下取得进展…只要等待
为了别的什么
考虑这个例子:
import asyncio
@asyncio.coroutine
def test1():
print("in test1")
@asyncio.coroutine
def dummy():
yield from asyncio.sleep(1)
print("dummy ran")
@asyncio.coroutine
def main():
test1()
yield from dummy()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
输出:
dummy ran
in test1
dummy ran
正如您所看到的,test1
从未实际执行过,因为我们没有显式地对它调用yield from
现在,如果我们使用asyncio.async
围绕test1
包装一个Task
实例,结果是不同的:
import asyncio
@asyncio.coroutine
def test1():
print("in test1")
@asyncio.coroutine
def dummy():
yield from asyncio.sleep(1)
print("dummy ran")
@asyncio.coroutine
def main():
asyncio.async(test1())
yield from dummy()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
输出:
dummy ran
in test1
dummy ran
因此,使用yield from asyncio.async(coro())
,实际上没有实际的理由,因为它比yield from coro()
慢,没有任何好处;它引入了将coro
添加到内部asyncio
调度程序的开销,但这不是必需的,因为使用yield from
可以保证coro
无论如何都会执行。如果您只想调用一个协程并等待它完成,只需直接从
协程中退出即可
旁注:
我正在使用asyncio.async
*而不是直接使用Task
:
不要直接创建Task
实例:使用async()
函数或
BaseEventLoop.create_task()
方法
*请注意,从Python 3.4.4开始,asyncio.async
被弃用,取而代之的是。如PEP 380中所述,引入yield from的公认PEP文档,表达式res=yield from f()
来自以下循环的思想:
for res in f():
yield res
这样,事情变得非常清楚:如果f()
是some\u coroutine()
,则执行coroutine。另一方面,如果f()some\u coroutine()
不会执行,只有新创建的生成器作为第一个参数传递给任务。\uuuuu init\uuuu
结论:
res=yield from some_coroutine()
=>coroutine继续执行并返回下一个值
res=yield from Task(some\u coroutine())
=>创建一个新任务,该任务存储一个未执行的some\u coroutine()
生成器对象
asyncio中根本没有优先级。对于裸协同路由,您必须使用yield from coro()
来运行协同路由,在任务构造的情况下,如async(coro())
将与其他并行执行协同路由。是的,您是对的。从技术上讲,yield from coro()
立即执行协同程序,async(coro())
通过循环调度执行。call_soon()
call。好吧,这是实现细节。Trollius不使用yield from
且与asyncio不完全兼容。与asyncio完全兼容的自定义事件循环利用yield from
并重用调用loop.call_soon()
的asyncio.Task。非100%兼容的系统可能会邀请自己的合同,并有自己的实施细节。是的,如果PyPy支持3.4(目前仅支持3.2),它将以与CPython 3.4相同的方式与协同程序一起工作。至少我这么认为,但不能保证。我是CPython核心开发人员,不是PyPy。