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