Asyncio prints the execution status of a coroutine

I have a bunch of coroutines that do some work

@asyncio.coroutine
def do_work():
    global COUNTER
    result = ...
    if result.status == 'OK':
        COUNTER += 1

      

and one more

COUNTER = 0
@asyncio.coroutine
def display_status():
    while True:
        print(COUNTER)
        yield from asyncio.sleep(1)

      

which should display how many coroutines have finished their work. How do you accomplish this task correctly? The following solution doesn't work

@asyncio.coroutine
def spawn_jobs():
    coros = []
    for i in range(10):
        coros.append(asyncio.Task(do_work()))
    yield from asyncio.gather(*coros)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.create_task(display_status())
    loop.run_until_complete(spawn_jobs())
    loop.close()

      

I expect the counter to be printed to the console every second no matter what the do_work () coroutines do. But I have only two outputs: 0 and after a few seconds I repeat 10.

+3


source to share


2 answers


But I only have two outputs: 0 and after a few seconds it repeats 10.

I cannot reproduce it. If I use:

import asyncio
import random

@asyncio.coroutine
def do_work():
    global COUNTER
    yield from asyncio.sleep(random.randint(1, 5))
    COUNTER += 1

      

I am getting output like this:

0
0
4
6
8
Task was destroyed but it is pending!
task: <Task pending coro=<display_status() running at most_wanted.py:16> wait_for=<Future pending cb=[Task._wakeup()] created at ../Lib/asyncio/tasks.py:490> created at most_wanted.py:27>

      



Endless loop in display_status()

raises a warning at the end. To avoid warning; exit the loop when all tasks in the package have been completed:

#!/usr/bin/env python3
import asyncio
import random
from contextlib import closing
from itertools import cycle

class Batch:
    def __init__(self, n):
        self.total = n
        self.done = 0

    async def run(self):
        await asyncio.wait([batch.do_work() for _ in range(batch.total)])

    def running(self):
        return self.done < self.total

    async def do_work(self):
        await asyncio.sleep(random.randint(1, 5)) # do some work here
        self.done += 1

    async def display_status(self):
        while self.running():
            await asyncio.sleep(1)
            print('\rdone:', self.done)

    async def display_spinner(self, char=cycle('/|\-')):
        while self.running():
            print('\r' + next(char), flush=True, end='')
            await asyncio.sleep(.3)

with closing(asyncio.get_event_loop()) as loop:
    batch = Batch(10)
    loop.run_until_complete(asyncio.wait([
        batch.run(), batch.display_status(), batch.display_spinner()]))

      

Output

done: 0
done: 2
done: 3
done: 4
done: 10

      

+1


source


Solution using a module threading

SHOW_STATUS = True
def display_status_sync():
    while SHOW_STATUS:
        print(S_REQ)
        time.sleep(1)

if __name__ == '__main__':
    new_thread = threading.Thread(target=display_status_sync)
    new_thread.start()
    loop.run_until_complete(spawn_jobs())
    SHOW_STATS = False
    new_thread.join()
    loop.close()

      



But I want to achieve similar functionality using asyncio coroutines. Is it possible to do this?

0


source







All Articles