我试图找出如何移植线程程序以使用asyncio
。我有很多代码可以围绕几个标准库Queues
进行同步,基本上就像这样:
import queue, random, threading, time
q = queue.Queue()
def produce():
while True:
time.sleep(0.5 + random.random()) # sleep for .5 - 1.5 seconds
q.put(random.random())
def consume():
while True:
value = q.get(block=True)
print("Consumed", value)
threading.Thread(target=produce).start()
threading.Thread(target=consume).start()
一个线程创建值(可能是用户输入),另一个线程用它们做某事。重点是这些线程在新数据之前处于空闲状态,此时它们会唤醒并对其执行某些操作。
我试图使用asyncio来实现这种模式,但我似乎无法弄清楚如何使用as" go"。
我的尝试或多或少看起来像这样(并且根本不做任何事情)。
import asyncio, random
q = asyncio.Queue()
@asyncio.coroutine
def produce():
while True:
q.put(random.random())
yield from asyncio.sleep(0.5 + random.random())
@asyncio.coroutine
def consume():
while True:
value = yield from q.get()
print("Consumed", value)
# do something here to start the coroutines. asyncio.Task()?
loop = asyncio.get_event_loop()
loop.run_forever()
我尝试过使用协同程序的变体,不使用它们,在任务中包装东西,试图让它们创建或返回期货等。
我开始认为我对如何使用asyncio有错误的想法(也许这种模式应该以我不知道的不同方式实现)。 任何指针将不胜感激。
答案 0 :(得分:37)
是的,确切地说。任务是你的朋友:
import asyncio, random
q = asyncio.Queue()
@asyncio.coroutine
def produce():
while True:
yield from q.put(random.random())
yield from asyncio.sleep(0.5 + random.random())
@asyncio.coroutine
def consume():
while True:
value = yield from q.get()
print("Consumed", value)
loop = asyncio.get_event_loop()
loop.create_task(produce())
loop.create_task(consume())
loop.run_forever()
asyncio.ensure_future
也可用于创建任务。
请注意:q.put()
是协程,因此您应该使用yield from q.put(value)
。
<强> UPD 强>
在示例中,从asyncio.Task()
/ asyncio.async()
切换到新品牌API loop.create_task()
和asyncio.ensure_future()
。
答案 1 :(得分:5)
这是我在制作中使用的内容,转移到要点:https://gist.github.com/thehesiod/7081ab165b9a0d4de2e07d321cc2391d
答案 2 :(得分:2)
稍后,也许OT,请记住,您可以从多个任务中消费Queue
,因为他们是独立的消费者。
以下代码段显示了如何使用asyncio
任务实现相同的线程池模式。
q = asyncio.Queue()
async def sum(x):
await asyncio.sleep(0.1) # simulates asynchronously
return x
async def consumer(i):
print("Consumer {} started".format(i))
while True:
f, x = await q.get()
print("Consumer {} procesing {}".format(i, x))
r = await sum(x)
f.set_result(r)
async def producer():
consumers = [asyncio.ensure_future(consumer(i)) for i in range(5)]
loop = asyncio.get_event_loop()
tasks = [(asyncio.Future(), x) for x in range(10)]
for task in tasks:
await q.put(task)
# wait until all futures are completed
results = await asyncio.gather(*[f for f, _ in tasks])
assert results == [r for _, r in tasks]
# destroy tasks
for c in consumers:
c.cancel()
asyncio.get_event_loop().run_until_complete(producer())