I am trying to read through the asyncio examples, but failed to find the simplest (in my viewpoint). Suppose I have a "normal" function that takes 1 sec. I simulate that with time.sleep(1) call. How can I wrap that function in a way that three calls would run asynchronously so the total execution time would be 1 sec?
I can do it by using threads, but not asyncio.
Here is an example:
import asyncio
import time
from threading import Thread
from datetime import datetime
from math import sqrt
def heavy_cpu(n):
print(f"{n} --> start: {datetime.now()}")
time.sleep(1)
# for i in range(5099999):
# _ = sqrt(i) * sqrt(i)
print(f"{n} --> finish: {datetime.now()}")
async def count(n):
await asyncio.sleep(0.0000001)
heavy_cpu(n)
async def main_async():
await asyncio.gather(count(1), count(2), count(3))
def test_async():
s = time.perf_counter()
asyncio.run(main_async())
elapsed = time.perf_counter() - s
print(f"asyncio executed in {elapsed:0.2f} seconds.")
# ========== asyncio vs threading =============
def main_thread():
threads = [Thread(target=heavy_cpu, args=(n,)) for n in range(1, 4)]
for t in threads:
t.start()
for t in threads:
t.join()
def test_thread():
s = time.perf_counter()
main_thread()
elapsed = time.perf_counter() - s
print(f"thread executed in {elapsed:0.2f} seconds.")
if __name__ == "__main__":
test_async()
test_thread()
The output:
1 --> start: 2020-05-12 18:28:53.513381
1 --> finish: 2020-05-12 18:28:54.517861
2 --> start: 2020-05-12 18:28:54.518162
2 --> finish: 2020-05-12 18:28:55.521757
3 --> start: 2020-05-12 18:28:55.521930
3 --> finish: 2020-05-12 18:28:56.522813
asyncio executed in 3.01 seconds.
1 --> start: 2020-05-12 18:28:56.523789
2 --> start: 2020-05-12 18:28:56.523943
3 --> start: 2020-05-12 18:28:56.524087
1 --> finish: 2020-05-12 18:28:57.5265992 --> finish: 2020-05-12 18:28:57.526689
3 --> finish: 2020-05-12 18:28:57.526849
thread executed in 1.00 seconds.
Question: why each asyncio finish step [1,2,3] takes 1 sec each? How do I make it truly async?