use*_*412 4 python sorting sleep python-asyncio
当我做出一个奇怪的发现时,我决定使用Python 实现睡眠排序(https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort)asyncio:它使用负值(并立即返回0)!
这是代码(你可以在这里运行https://repl.it/DYTZ):
import asyncio
import random
async def sleepy(value):
return await asyncio.sleep(value, result=value)
async def main(input_values):
result = []
for sleeper in asyncio.as_completed(map(sleepy, input_values)):
result.append(await sleeper)
print(result)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
input_values = list(range(-5, 6))
random.shuffle(input_values)
loop.run_until_complete(main(input_values))
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,代码需要5秒才能执行,但结果总是如此[0, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5].我可以理解0立即返回,但负值如何以正确的顺序返回?
好吧,看看来源:
delay == 0 是特殊的,立即返回,它甚至没有尝试睡觉.events.get_event_loop().由于没有调用events.set_event_loop_policy(policy)in asyncio.tasks,它似乎会回退到默认值,除非它已经被设置在其他地方,默认是asyncio.DefaultEventLoopPolicy.events.py,因为它在Windows上与UNIX上不同.sleep电话loop.create_future().这已经定义了一些遗传,过去了base_events.BaseEventLoop.它只是对Future()构造函数的简单调用,没有重要的逻辑.从Future它的实例委托回到循环,如下所示:
future._loop.call_later(delay,
futures._set_result_unless_cancelled,
future, result)
Run Code Online (Sandbox Code Playgroud)BaseEventLoop,但仍然没有直接处理delay数字:它调用self.call_at,将当前时间添加到延迟.call_at调度并返回一个events.TimerHandle,回调就是告诉Future它已完成.返回值仅在要取消任务时才相关,它最终会自动清除.调度是重要的一点._scheduled排序通过heapq- 一切按顺序排列,计时器按其排序_when.这是关键.TL; DR:
asyncio在负面持续时间内睡觉安排任务在过去"准备好".这意味着它们会到达计划任务列表的顶部,并在事件循环检查后立即运行.实际上,0首先是因为它甚至没有安排,但是其他所有内容都以"迟到"的形式注册到调度程序,并按照其迟到的顺序立即处理.