等同于asyncio.Queues与worker" threads"

时间:2014-05-26 06:53:37

标签: python python-3.x queue python-asyncio

我试图找出如何移植线程程序以使用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有错误的想法(也许这种模式应该以我不知道的不同方式实现)。 任何指针将不胜感激。

3 个答案:

答案 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())