为什么运行异步协程不会放弃控制权?

时间:2018-12-27 17:17:00

标签: 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 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()

该代码有望使两个功能并行运行。我的意思是两者的输出应同时出现。但这没有发生。原因是我自己asyncsleep实现了睡眠功能。如果我使用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函数没有的asyncsleep函数是什么?他们都是协程,为什么它们表现不同?

2 个答案:

答案 0 :(得分:2)

异步不是线程。异步代码只有在等待或功能完成后才会放弃控制。您的睡眠功能不会放弃控制,所以:

asyncio循环正在运行,并且已调度do_one和do_two。循环选择运行do_one,因为您不屈服或等待代码,直到函数完成后才返回循环。

答案 1 :(得分:1)

当您执行异步操作时,您不会连续进行。有一个event loop,它有一个tasks池并在它们之间切换:当当前任务await时,循环将控制权传递给池中的其他任务之一。

time.sleep是同步的,就像@ user2357112在评论中所说的那样,它只是阻塞执行一段时间,而没有机会进行其他协程。

因此,asyncio.sleep有什么,而您的asyncsleep没有:

  • 它会创建一个新的Future(一个特殊对象,表示尚未完成 的任务的结果)
  • 该新任务不执行任何操作,但是需要指定的时间
  • 因此,新的未来将在时机成熟时产生result
  • 该任务有助于阻止等待asyncio.sleep的流程,但不会阻止其他任务。

感受不同。