How to write your own async/awaitable coroutine function in Python?
I found a concurrency/asynchronous approach using generators. However, it's not an asyncio
approach:
from collections import deque
def coro1():
for i in range(1, 5):
yield i
def coro2():
for i in range(1, 5):
yield i*10
print('Async behaviour using default list with O(n)'.center(60, '#'))
tasks = list()
tasks.extend([coro1(), coro2()])
while tasks:
task = tasks.pop(0)
try:
print(next(task))
tasks.append(task)
except StopIteration:
pass
print('Async behaviour using deque with O(1)'.center(60, '#'))
tasks = deque()
tasks.extend([coro1(), coro2()])
while tasks:
task = tasks.popleft() # select and remove a task (coro1/coro2).
try:
print(next(task))
tasks.append(task) # add the removed task (coro1/coro2) for permutation.
except StopIteration:
pass
Out:
########Async behaviour using default list with O(n)########
1
10
2
20
3
30
4
40
###########Async behaviour using deque with O(1)############
1
10
2
20
3
30
4
40
[UPDATE]:
Finally, I've solved this example through asyncio
syntax:
import asyncio
async def coro1():
for i in range(1, 6):
print(i)
await asyncio.sleep(0) # switches task every one iteration.
async def coro2():
for i in range(1, 6):
print(i * 10)
await asyncio.sleep(0) # switches task every one iteration.
loop = asyncio.get_event_loop()
futures = [
asyncio.ensure_future(coro1()),
asyncio.ensure_future(coro2())
]
loop.run_until_complete(asyncio.gather(*futures))
loop.close()
Out:
1
10
2
20
3
30
4
40
5
50
And another concurrency coroutine approach via async-await
expression and an event-loop manager based on Heap queue algorithm, without using asyncio
library and its event-loop as well as without using asyncio.sleep()
method:
import heapq
from time import sleep
from datetime import datetime, timedelta
class Sleep:
def __init__(self, seconds):
self.sleep_until = datetime.now() + timedelta(seconds=seconds)
def __await__(self):
yield self.sleep_until
async def coro1():
for i in range(1, 6):
await Sleep(0)
print(i)
async def coro2():
for i in range(1, 6):
await Sleep(0)
print(i * 10)
def coro_manager(*coros):
coros = [(datetime.now(), coro) for coro in coros]
heapq.heapify(coros)
while coros:
exec_at, coro = heapq.heappop(coros)
if exec_at > datetime.now():
sleep((exec_at - datetime.now()).total_seconds())
try:
heapq.heappush(coros, (coro.send(None), coro))
except StopIteration:
try:
coros.remove(coro)
except ValueError:
pass
coro_manager(coro1(), coro2())
Out:
1
10
2
20
3
30
4
40
5
50