在后台处理异步迭代器

huangapple go评论71阅读模式
英文:

Process an Asynchronous Iterator in background

问题

I trying to process an asynchronous iterator in background.

I can process in the main function:

target = ...
async def main():
  async for item in target.listen():
    print(item) # works fine

  print('done') # never arrives, because loop iterates forever

asyncio.run(main())

But doing it this way, the code is blocking.

So I try process the iterator in other function with create_task, but the loop never iterates.

target = ...
async def process():
  async for item in target.listen():
    print(item) # never print

async def main():
  asyncio.create_task(process())
  print('done') # works

asyncio.run(main())

Is it possible to process an asynchronous iterator in background? How?

英文:

I trying to process an asynchronous iterator in background.

I can process in the main function:

target = ...
async def main():
  async for item in target.listen():
    print(item) # works fine

  print('done') # never arrives, because loop iterates forever

asyncio.run(main())

But doing it this way, the code is blocking.

So I try process the iterator in other function with create_task, but the loop never iterates.

target = ...
async def process():
  async for item in target.listen():
    print(item) # never print

async def main():
  asyncio.create_task(process())
  print('done') # works

asyncio.run(main())

Is it possible to process an asynchronous iterator in background? How?

答案1

得分: 1

如果您调用create_task()然后立即退出 - 这是您在代码中正在做的事情 - 那么任务当然不会运行。只有在前台执行某事,才能在“后台”运行某事,而您没有这样做。

即使您的main函数不立即退出,您的后台任务仍不会运行。Asyncio提供并发执行,但不提供并行执行 - 除非当前任务通过调用await来让出控制权,否则其他任务不会执行。

这是一个工作示例;我已经用一个简单的单词列表替换了您的target变量,以便我们可以迭代:

import asyncio

target = "one two three four five six".split()

async def process():
    for item in target:
        print(item)  # 不会立即打印
        await asyncio.sleep(0.3)

async def main():
    task = asyncio.create_task(process())
    while not task.done():
        print("在等待时做一些事情")
        await asyncio.sleep(1)
    print("完成")

asyncio.run(main())

运行上述代码会产生以下输出:

在等待时做一些事情
one
two
three
four
在等待时做一些事情
five
six
完成

与我在此示例中所做的检查task.done()不同,您在实践中更有可能使用其中的一个等待原语asyncio.gather 来等待后台任务的完成。

英文:

If you call create_task() and then immediately exit -- which is what you're doing in your code -- then of course the task never runs. You can only run something "in the background" if you're doing something in the foreground, and you're not.

Even if your main function wasn't exiting immediately, your background task still wouldn't run. Asyncio provides concurrent execution, but not parallel execution -- other tasks won't execute unless the current task yields control by calling await.

Here's a working example; I've replaced your target variable with a simple list of words just so we have something over which to iterate:

import asyncio

target = "one two three four five six".split()


async def process():
    for item in target:
        print(item)  # never print
        await asyncio.sleep(0.3)


async def main():
    task = asyncio.create_task(process())
    while not task.done():
        print("doing something while waiting")
        await asyncio.sleep(1)
    print("done")


asyncio.run(main())

Running the above code produces:

doing something while waiting
one
two
three
four
doing something while waiting
five
six
done

Rather than checking for task.done() as I've done in this example, you would in practice be more likely to use one of the waiting primitives or asyncio.gather to wait for the completion of background tasks.

huangapple
  • 本文由 发表于 2023年2月18日 08:00:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490271.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定