如何与asyncio同时运行无限循环?

时间:2017-12-11 03:20:29

标签: python concurrency python-asyncio event-loop

等待时如何继续下一个循环?例如:

AjaxControlToolkit.CalendarExtender calender = (AjaxControlToolkit.CalendarExtender)DetailsView3.FindControl("txbkirim");
calender.SelectedDate = DateTime.Now.Date;

如何使async def get_message(): # async get message from queue return message async process_message(message): # make some changes on message return message async def deal_with_message(message): # async update some network resource with given message async def main(): while True: message = await get_message() message = await process_message(message) await deal_with_message(message) loop = asyncio.get_event_loop() loop.run_until_complete(main()) 循环并发?如果它正在等待while True,它可以转到下一个循环并运行deal_with_message

被修改

我想我找到了一个解决方案:

get_message

2 个答案:

答案 0 :(得分:3)

您的解决方案可行,但我发现问题。

A

一旦B启动它就会立即创建新任务并立即发生(async def main(): asyncio.ensure_future(main()) # task finishing 立即创建任务),这与需要时间的此任务的实际完成不同。我想这可能会导致创造大量的任务,从而耗尽你的RAM。

除此之外,它意味着可以同时运行任何大量的任务。它可以消耗你的网络吞吐量或可以同时打开的套接字数量(想象一下你并不想并行下载1 000 000个网址 - 没有任何好处会发生。)

在并发世界中,这个问题通常是can be solved,它通过使用类似Semaphore之类的内容来限制可以同时运行某些合理值的事物的数量。在您的情况下,我认为手动跟踪正在运行的任务量并手动填充它更方便:

main

输出将如下:

ensure_future

这里重要的部分是我们如何在运行任务量减少到少于5之后才能使用下一条消息。

<强> UPD:

是的,如果您不需要动态更改最大运行数,信号量似乎更方便。

import asyncio
from random import randint


async def get_message():
    message = randint(0, 1_000)
    print(f'{message} got')
    return message


async def process_message(message):
    await asyncio.sleep(randint(1, 5))
    print(f'{message} processed')
    return message


async def deal_with_message(message):
    await asyncio.sleep(randint(1, 5))
    print(f'{message} dealt')


async def utilize_message():
    message = await get_message()
    message = await process_message(message)
    await deal_with_message(message)


parallel_max = 5  # don't utilize more than 5 msgs parallely
parallel_now = 0


def populate_tasks():
    global parallel_now
    for _ in range(parallel_max - parallel_now):
        parallel_now += 1
        task = asyncio.ensure_future(utilize_message())
        task.add_done_callback(on_utilized)


def on_utilized(_):
    global parallel_now
    parallel_now -= 1
    populate_tasks()


if __name__ ==  '__main__':
    loop = asyncio.get_event_loop()
    try:
        populate_tasks()
        loop.run_forever()
    finally:
        loop.run_until_complete(loop.shutdown_asyncgens())
        loop.close()

答案 1 :(得分:1)

最简单的解决方案是asyncio.ensure_future

async def main():
    tasks = []
    while running:
        message = await get_message()
        message = await process_message(message)
        coroutine = deal_with_message(message)
        task = asyncio.ensure_future(coroutine) # starts running coroutine
        tasks.append(task)
    await asyncio.wait(tasks)

如果可以在最后等待所有任务,那么自己跟踪任务是可选的。

async def main():
    while running:
        message = await get_message()
        message = await process_message(message)
        coroutine = deal_with_message(message)
        asyncio.ensure_future(coroutine)
    tasks = asyncio.Task.all_tasks()
    await asyncio.wait(tasks)