Python 为什么运行异步协程不能恢复控制?
我有一个示例代码:Python 为什么运行异步协程不能恢复控制?,python,python-3.x,asynchronous,python-asyncio,Python,Python 3.x,Asynchronous,Python Asyncio,我有一个示例代码: import asyncio import time async def asyncsleep(number): time.sleep(number) async def do_one(): await asyncsleep(1) print("one 1") await asyncsleep(1) print("one 2") await asyncsleep(1) print("one 3") async d
import asyncio
import time
async def asyncsleep(number):
time.sleep(number)
async def do_one():
await asyncsleep(1)
print("one 1")
await asyncsleep(1)
print("one 2")
await asyncsleep(1)
print("one 3")
async def do_two():
await asyncsleep(1)
print("two 1")
await asyncsleep(1)
print("two 2")
await asyncsleep(1)
print("two 3")
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([
do_one(),
do_two()
]))
loop.close()
这段代码期望两个函数并行运行。我的意思是两者的产出应该同时出现。但事实并非如此。原因是我自己实现了一个sleep函数asynchsleep
。如果我使用asyncio.sleep
代替它,一切都会正常工作
import asyncio
import time
async def asyncsleep(number):
time.sleep(number)
async def do_one():
await asyncio.sleep(1)
print("one 1")
await asyncio.sleep(1)
print("one 2")
await asyncio.sleep(1)
print("one 3")
async def do_two():
await asyncio.sleep(1)
print("two 1")
await asyncio.sleep(1)
print("two 2")
await asyncio.sleep(1)
print("two 3")
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([
do_one(),
do_two()
]))
loop.close()
我还查找了asyncio.sleep
函数的签名:
@coroutine
def sleep(delay, result=None, *, loop=None):
"""Coroutine that completes after a given time (in seconds)."""
if delay == 0:
yield
return result
if loop is None:
loop = events.get_event_loop()
future = loop.create_future()
h = future._loop.call_later(delay,
futures._set_result_unless_cancelled,
future, result)
try:
return (yield from future)
finally:
h.cancel()
asyncio.sleep
函数有什么是我实现的asyncio.sleep
函数没有的?它们都是协程,为什么它们的行为不同呢?当你做异步的事情时,你没有连续的流程。有一个,在它们之间有一个and池:当当前任务等待时,循环将控制传递给池中的一个其他任务
,正如@user2357112在注释中优雅地指出的那样,它是同步的,它只是在一段时间内阻止执行,而没有提供继续执行其他协同程序的机会
那么,asyncio.sleep
有什么,而您的asyncio.sleep
没有什么:
- 它创建一个新对象(表示尚未完成的任务的结果的特殊对象)
- 新任务不执行任何操作,但需要指定的时间
- 因此,新的未来将在时机成熟时产生
结果
- 该任务有助于阻止等待
的流,但不会阻止其他任务asyncio.sleep
感受差异。当你做异步的事情时,你没有连续的流程。有一个,在它们之间有一个and池:当当前任务等待时,循环将控制传递给池中的一个其他任务 ,正如@user2357112在注释中优雅地指出的那样,它是同步的,它只是在一段时间内阻止执行,而没有提供继续执行其他协同程序的机会 那么,
asyncio.sleep
有什么,而您的asyncio.sleep
没有什么:
- 它创建一个新对象(表示尚未完成的任务的结果的特殊对象)
- 新任务不执行任何操作,但需要指定的时间
- 因此,新的未来将在时机成熟时产生
结果
- 该任务有助于阻止等待
的流,但不会阻止其他任务asyncio.sleep
感受差异。异步不是线程。异步代码在遇到等待或函数完成之前不会放弃控制。您的睡眠功能不会放弃控制,因此:
asyncio循环正在运行,计划执行一个和两个操作。循环选择运行dou_one,因为您不会屈服或等待代码返回到循环,直到函数完成 异步不是线程。异步代码在遇到等待或函数完成之前不会放弃控制。您的睡眠功能不会放弃控制,因此:
asyncio循环正在运行,计划执行一个和两个操作。循环选择运行dou_one,因为您不会屈服或等待代码返回到循环,直到函数完成
时间。睡眠是同步的。如果time.sleep
像那样工作,asyncio.sleep
不存在。@user2357112不是asyncio
将同步包装为异步的原因吗?在异步函数中插入同步调用并不能使其异步。@dirn:time.sleep
不受CPU限制。@TechJS从技术上讲,每个函数调用都是阻塞的(它会阻止调用线程,直到函数返回或引发),但在这种情况下,像list.append
这样的函数在很短的时间内完成它们的工作,而time.sleep
或sock.recv
这样的函数可以无限期地阻塞线程。解决方案是不调用此类函数,而是使用它们的异步变量。这就是asyncio所做的,使用s当协同路由等待的条件(例如asyncio.sleep)出现时,使用一些额外的魔法来暂停协同路由还没有准备好。time.sleep
是同步的。如果time.sleep
像这样工作,asyncio.sleep
就不存在了。@user2357112不是asyncio
将同步包装成异步的原因吗?在异步函数中插入同步调用不会使其异步。@dirn:time.sleep
不是“t CPU绑定。@TechJS从技术上讲,每个函数调用都是阻塞的(它会阻塞调用线程,直到函数返回或引发),但在这种情况下,像list.append
这样的函数在很短的时间内完成它们的工作,而time.sleep
或sock.recv
这样的函数可以无限期地阻塞线程。解决方案是不调用此类函数,而是使用它们的异步变量。这就是asyncio所做的,使用s当协程所等待的条件(如asyncio.sleep)尚未就绪时,可以使用一些额外的魔法来暂停协程。