Python 协同程序进度的异步打印状态

Python 协同程序进度的异步打印状态,python,python-3.x,asynchronous,coroutine,Python,Python 3.x,Asynchronous,Coroutine,我有很多同事在做一些工作 @asyncio.coroutine def do_work(): global COUNTER result = ... if result.status == 'OK': COUNTER += 1 还有一个 COUNTER = 0 @asyncio.coroutine def display_status(): while True: print(COUNTER) yield from

我有很多同事在做一些工作

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

COUNTER = 0
@asyncio.coroutine
def display_status():
    while True:
        print(COUNTER)
        yield from asyncio.sleep(1)
它们必须显示有多少协同程序已经完成了它们的工作。如何做好这项工作??以下解决方案不起作用

@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()

我希望无论协作程序做什么,计数器都会每秒打印到控制台。但我只有两个输出:0,几秒钟后重复10。

使用
线程化
模块解决方案

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()
但我希望使用asyncio协程实现类似的功能。有可能吗

但我只有两个输出:0和几秒钟后重复10

我无法复制它。如果我使用:

import asyncio
import random

@asyncio.coroutine
def do_work():
    global COUNTER
    yield from asyncio.sleep(random.randint(1, 5))
    COUNTER += 1
我得到如下输出:

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>
输出
一个可能的选择是将打印(计数器)添加到
do_work()
函数中,但我希望每秒打印
COUNTER
,而不是在完成一件工作后,“不工作”不是很具体。你预计会发生什么?会发生什么情况?不要在注释中添加其他信息,而是在你的问题中添加。无关:使用
asyncio.create_task()
而不是
asyncio.task()
。此外,在这种情况下,这两种方法都不需要:
yield from asyncio.wait([do\u work()for u in range(10)])
按原样工作。我也可以使用
loop.run\u in\u executor(无,显示状态\u sync)
而不是创建线程。这将产生相同的效果。问题在于在
do\u work()
中使用同步代码。我使用同步调用
r=requests.get('http://httpbin.org/get)
所以他们会阻止我的显示状态协同程序。似乎我需要切换到aiohttp来发出请求。当我插入
r=yield from aiohttp.request('POST','http://httpbin.org/post“,data=data)
我可以做不到512个批处理作业,而不是sleep()。否则我会出现一个错误:
运行时错误:事件循环已关闭
。“这是aiohttp限制还是其他什么?”莫斯特温特:你应该问另外一个问题,启用,包括完整的回溯。我猜,您需要类似于
result=yield from r.json()
的内容来读取响应。
#!/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()]))
done: 0
done: 2
done: 3
done: 4
done: 10