当我做出一个奇怪的发现时,我决定使用Python的asyncio
实现睡眠排序(https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort):它使用负值(并立即返回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))
代码需要5秒才能执行,如预期的那样,但结果总是[0, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5]
。我可以理解0立即返回,但负值如何以正确的顺序返回?
答案 0 :(得分:5)
好吧,看看source:
ValidTeachers
特别容易立即返回,它甚至不会尝试睡觉。delay == 0
。由于events.get_event_loop()
中没有events.set_event_loop_policy(policy)
来电,因此除非已将其设置在其他位置the default is asyncio.DefaultEventLoopPolicy
,否则它似乎会回到默认状态。asyncio.tasks
中未定义此内容,因为Windows上UNIX上的内容有所不同。events.py
都会调用sleep
。这在base_events.BaseEventLoop
中定义了一些遗产。它只是对loop.create_future()
构造函数的简单调用,没有重要逻辑。从Future()
的实例中,它委托回循环,如下所示:
Future
future._loop.call_later(delay,
futures._set_result_unless_cancelled,
future, result)
,并且仍然没有直接处理BaseEventLoop
号码:它会调用delay
,将当前时间添加到延迟。self.call_at
计划并返回call_at
,回调就是告诉events.TimerHandle
它已完成。返回值仅在要取消任务时才相关,它最终会自动清除。调度是重要的一点。Future
通过_scheduled
排序 - 所有内容按排序顺序排列,计时器按其heapq
排序。这是关键。<强> TL; DR:强>
与_when
睡觉持续时间为负,安排任务准备就绪&#34;在过去。这意味着它们会到达计划任务列表的顶部,并在事件循环检查后立即运行。实际上,0首先是因为它甚至没有安排,但是其他一切都注册到调度程序,因为&#34;运行迟到&#34;并按照有多晚的顺序立即处理。
答案 1 :(得分:4)
如果您查看asyncio来源,sleep
special cases 0并立即返回。
if delay == 0:
yield
return result
如果您继续浏览源代码,您会发现任何其他值都会传递到事件循环的call_later
方法。查看如何为默认循环(call_later
)实施BaseEventLoop
,您会看到call_later
passes a time to call_at
。
self.call_at(self.time() + delay, callback, *args)
按顺序转换值的原因是负延迟创建的时间发生在具有正延迟的时间之前。