为什么我需要将一个 python 协程包装成一个 task/when 才能使用任务或协程?
Why do I need to wrap a python coroutine into a task/when to use a task or a coroutine?
在python中,有3 main types awaitable objects:协程、任务和Futures。
我可以await
一个协程,还有一个tasks
。
等待协程
import asyncio
async def nested():
return 42
async def main():
print(await nested()) # will print "42".
asyncio.run(main())
等待任务
import asyncio
async def nested():
return 42
async def main():
task = asyncio.create_task(nested())
await task
asyncio.run(main())
首先将协程包装在任务中的价值是什么?看起来他们做同样的事情。
我什么时候需要使用任务还是协程?
创建 Task
将传递的协程安排在事件循环中 运行。您可以使用 Task
取消底层协程。
在这种情况下,没有真正的区别:通过等待协程,它将作为任务的一部分进行调度。然而,这意味着它是由其父级驱动的。
通过将协程包装在任务中,它可以在事件循环中独立调度,这意味着它不再由包含任务驱动(它有自己的生命周期)并且可以与它进行更丰富的交互(例如取消或向其添加回调)。
认真思考“函数”与“线程”。协程只是一个可以暂停的函数(如果它等待东西),但它仍然只存在于其调用者的词汇和动态上下文中。任务从该上下文中释放出来,它使包装的协程过自己的生活,就像线程使包装的函数(目标)过自己的生活一样。
Coroutine 只是 运行 在当前 awaitable 上下文中的一个函数。它可以代表调用者(调用await
的人)让出执行事件循环。想想一个允许暂停它的线程的函数。您可以从一个协程调用另一个协程,但它们仍然共享同一个线程。
另一方面,Task 立即将单独的 job 发布到事件循环。任务本身是该作业的句柄。您可以 await
一个任务,但它可以 运行 在“并行”中对自己很好——在单线程上下文中,这意味着该任务可以 运行 而其他作业正在屈服(例如等待I/O)。任务甚至可能在您调用 await
.
之前完成
没有任务的例子:
job_1 = sleep(5)
job_2 = sleep(2)
# will sleep for 5 seconds
await job_1
# will sleep for another 2 seconds
await job_2
任务示例:
job_1 = sleep(5)
job_2 = asyncio.create_task(sleep(2))
# will sleep for 5 seconds
await job_1
# by this time, job_2 is complete
# because previous job has yielded at some point, allowing other jobs to run
# thus await takes no time
await job_2
在python中,有3 main types awaitable objects:协程、任务和Futures。
我可以await
一个协程,还有一个tasks
。
等待协程
import asyncio
async def nested():
return 42
async def main():
print(await nested()) # will print "42".
asyncio.run(main())
等待任务
import asyncio
async def nested():
return 42
async def main():
task = asyncio.create_task(nested())
await task
asyncio.run(main())
首先将协程包装在任务中的价值是什么?看起来他们做同样的事情。
我什么时候需要使用任务还是协程?
创建 Task
将传递的协程安排在事件循环中 运行。您可以使用 Task
取消底层协程。
在这种情况下,没有真正的区别:通过等待协程,它将作为任务的一部分进行调度。然而,这意味着它是由其父级驱动的。
通过将协程包装在任务中,它可以在事件循环中独立调度,这意味着它不再由包含任务驱动(它有自己的生命周期)并且可以与它进行更丰富的交互(例如取消或向其添加回调)。
认真思考“函数”与“线程”。协程只是一个可以暂停的函数(如果它等待东西),但它仍然只存在于其调用者的词汇和动态上下文中。任务从该上下文中释放出来,它使包装的协程过自己的生活,就像线程使包装的函数(目标)过自己的生活一样。
Coroutine 只是 运行 在当前 awaitable 上下文中的一个函数。它可以代表调用者(调用await
的人)让出执行事件循环。想想一个允许暂停它的线程的函数。您可以从一个协程调用另一个协程,但它们仍然共享同一个线程。
Task 立即将单独的 job 发布到事件循环。任务本身是该作业的句柄。您可以 await
一个任务,但它可以 运行 在“并行”中对自己很好——在单线程上下文中,这意味着该任务可以 运行 而其他作业正在屈服(例如等待I/O)。任务甚至可能在您调用 await
.
没有任务的例子:
job_1 = sleep(5)
job_2 = sleep(2)
# will sleep for 5 seconds
await job_1
# will sleep for another 2 seconds
await job_2
任务示例:
job_1 = sleep(5)
job_2 = asyncio.create_task(sleep(2))
# will sleep for 5 seconds
await job_1
# by this time, job_2 is complete
# because previous job has yielded at some point, allowing other jobs to run
# thus await takes no time
await job_2