user1475412 user1475412 - 3 months ago 7
Python Question

How does asyncio.sleep work with negative values?

I decided to implement sleep sort (https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort) using Python's

asyncio
when I made a strange discovery: it works with negative values (and returns immediately with 0)!

Here is the code (you can run it here 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))


The code takes 5 seconds to execute, as expected, but the result is always
[0, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5]
. I can understand 0 returning immediately, but how are the negative values coming back in the right order?

Answer

If you take a look at the asyncio source, sleep special cases 0 and returns immediately.

if delay == 0:
    yield
    return result

If you continue through the source, you'll see that any other value gets passed through to the event loop's call_later method. Looking at how call_later is implemented for the default loop (BaseEventLoop), you'll see that call_later passes a time to call_at.

self.call_at(self.time() + delay, callback, *args)

The reason the values are turned in order is that the times created with negative delays occur before those with positive delays.