The problem is related to the async module
Question:
my code:
import asyncio
async def count(counter):
print(f"number of entries in the list {len(counter)}")
while True:
await asyncio.sleep(1 / 1000)
counter.append(1)
async def print_every_sec(counter):
while True:
await asyncio.sleep(1)
print(f"- 1 secund later. " f"number of entries in the list: {len(counter)}")
async def print_every_5_sec():
while True:
await asyncio.sleep(5)
print(f"---- 5 secund later")
async def print_every_10_sec():
while True:
await asyncio.sleep(10)
print(f"---------- 10 secund later")
async def main():
counter = list()
tasks = [
count(counter),
print_every_sec(counter),
print_every_5_sec(),
print_every_10_sec(),
]
await asyncio.gather(*tasks)
asyncio.run(main())
This is my conclusion but is not correct.
Correct conclusion around 1000 for each iteration.
I don’t now what is it. This code works fine in online interpretations.
Answers:
The assumption that asyncio.sleep(1 / 1000)
(and to return control to other async routines) takes exactly one millisecond is not true.
Here’s a more interesting example that records how long the sleep
(and the time.perf_counter_ns()
invocation) actually took:
import asyncio
import statistics
import time
max_count = 2500
async def count(counter):
while len(counter) < max_count:
t0 = time.perf_counter_ns()
await asyncio.sleep(1 / 1000)
t1 = time.perf_counter_ns()
counter.append((t1 - t0) / 1_000_000)
async def print_every_sec(counter):
while len(counter) < max_count:
await asyncio.sleep(1)
print(f'count: {len(counter)}; average: {statistics.mean(counter)} ms')
async def main():
counter = list()
tasks = [
count(counter),
print_every_sec(counter),
]
await asyncio.gather(*tasks)
asyncio.run(main())
On my Macbook, Python 3.9, etc, etc., the result is
count: 744; average: 1.341670
count: 1494; average: 1.33668
count: 2248; average: 1.33304
count: 2500; average: 1.325463428
so it takes 30% more than we expected to.
For sleeps of 10ms, the average is 11.84 ms. For sleeps of 100ms, the average is 102.9 ms.
AKX, thank you very much, but your program does not work for me correctly. I don’t know why, but the program works with some delay. Maybe you know how to fix it?
count: 63; average: 15.537607936507937 ms
count: 127; average: 15.577350393700787 ms
count: 191; average: 15.570997382198954 ms
count: 255; average: 15.596465490196078 ms
count: 319; average: 15.611289968652038 ms
count: 383; average: 15.608178851174936 ms
count: 447; average: 15.609837360178972 ms
my code:
import asyncio
async def count(counter):
print(f"number of entries in the list {len(counter)}")
while True:
await asyncio.sleep(1 / 1000)
counter.append(1)
async def print_every_sec(counter):
while True:
await asyncio.sleep(1)
print(f"- 1 secund later. " f"number of entries in the list: {len(counter)}")
async def print_every_5_sec():
while True:
await asyncio.sleep(5)
print(f"---- 5 secund later")
async def print_every_10_sec():
while True:
await asyncio.sleep(10)
print(f"---------- 10 secund later")
async def main():
counter = list()
tasks = [
count(counter),
print_every_sec(counter),
print_every_5_sec(),
print_every_10_sec(),
]
await asyncio.gather(*tasks)
asyncio.run(main())
This is my conclusion but is not correct.
Correct conclusion around 1000 for each iteration.
I don’t now what is it. This code works fine in online interpretations.
The assumption that asyncio.sleep(1 / 1000)
(and to return control to other async routines) takes exactly one millisecond is not true.
Here’s a more interesting example that records how long the sleep
(and the time.perf_counter_ns()
invocation) actually took:
import asyncio
import statistics
import time
max_count = 2500
async def count(counter):
while len(counter) < max_count:
t0 = time.perf_counter_ns()
await asyncio.sleep(1 / 1000)
t1 = time.perf_counter_ns()
counter.append((t1 - t0) / 1_000_000)
async def print_every_sec(counter):
while len(counter) < max_count:
await asyncio.sleep(1)
print(f'count: {len(counter)}; average: {statistics.mean(counter)} ms')
async def main():
counter = list()
tasks = [
count(counter),
print_every_sec(counter),
]
await asyncio.gather(*tasks)
asyncio.run(main())
On my Macbook, Python 3.9, etc, etc., the result is
count: 744; average: 1.341670
count: 1494; average: 1.33668
count: 2248; average: 1.33304
count: 2500; average: 1.325463428
so it takes 30% more than we expected to.
For sleeps of 10ms, the average is 11.84 ms. For sleeps of 100ms, the average is 102.9 ms.
AKX, thank you very much, but your program does not work for me correctly. I don’t know why, but the program works with some delay. Maybe you know how to fix it?
count: 63; average: 15.537607936507937 ms
count: 127; average: 15.577350393700787 ms
count: 191; average: 15.570997382198954 ms
count: 255; average: 15.596465490196078 ms
count: 319; average: 15.611289968652038 ms
count: 383; average: 15.608178851174936 ms
count: 447; average: 15.609837360178972 ms