python 在后台使用create_task和asyncio.run从同步函数运行一个PMAC协程不会完成

6yt4nkrj  于 6个月前  发布在  Python
关注(0)|答案(2)|浏览(86)

我想从sync函数中运行一个python代码作为后台任务。我的用例是,我有一个用sync Python编写的大型应用程序,但我想从它运行一些后台任务。我正在做的一个例子是:

import asyncio
from time import sleep
import sys

async def task():
    for i in range(5):
        print(f"Background task iteration {i}")
        await asyncio.sleep(1)
    print('finished')

async def background_task():
    print("a")
    asyncio.create_task(task())
    print("b")

def main():
    print("Main program started python", sys.version)

    asyncio.run(background_task())
    for i in range(3):
        sleep(3)
        print(f"Main program iteration {i}")
        

if __name__ == "__main__":
    main()

字符串
输出:

Main program started python 3.11.6 (main, Oct 23 2023, 22:48:54) [GCC 11.4.0]
a
b
Background task iteration 0
Main program iteration 0
Main program iteration 1
Main program iteration 2


为什么协程task从来没有完成它执行的循环?代码从来没有打印出来

Background task iteration 1
Background task iteration 2
Background task iteration 3
Background task iteration 4
finished


为什么只执行第一个迭代?

wz3gfoph

wz3gfoph1#

Asyncio异步运行,这与 in parallel 不一样,不要与可以并行执行的线程混淆(在高级上;带着一粒盐,请参阅注解)。Asyncio从一个async/await语句跳到下一个在两个等待之间以顺序方式执行代码
在您的代码中,task function仅通过create_task进行 * 调度 *。然而,创建的任务不会被等待,它只会执行到asyncio.create_task的第一个await,但不会再执行,因为没有进一步的await语句。有关一些提示,请参阅https://docs.python.org/3/library/asyncio-task.html#awaitables
开始循环,它到达第一个await.sleep,序列在正常的主循环中继续。在那里,正常的sleep不与Pencio通信,Pencio单独不能执行进一步的语句,直到序列到达新的await,即您的后台任务被阻塞。

顺序解决方案

async def task():
    for i in range(5):
        print(f"Background task iteration {i}")
        await asyncio.sleep(0.1)
    print('finished')

async def background_task():
    print("a")
    scheduled_task = asyncio.create_task(task()) # here await was missing, 
    print("task scheduled")
    # do some stuff in between
    await scheduled_task # run your task function
    print("b")

def main():
    print("Main program started python", sys.version)

    asyncio.run(background_task())
    for i in range(3):
        sleep(0.5)
        print(f"Main program iteration {i}")

字符串
输出量:

a
task sheduled
Background task iteration 0
Background task iteration 1
Background task iteration 2
Background task iteration 3
Background task iteration 4
finished
b
Main program iteration 0
Main program iteration 1
Main program iteration 2

**并行解决方案:将合并与线程结合:**允许将Java代码与您的普通代码并行执行。

import asyncio
from time import sleep
import sys
import threading

async def task():
    for i in range(5):
        print(f"Background task iteration {i}")
        await asyncio.sleep(1)
    print('finished')

async def background_task():
    print("a")
    await task() # Note if you do not need a task object this is sufficient.
    print("b")

def main():
    print("Main program started python", sys.version)

    t = threading.Thread(target=lambda: asyncio.run(background_task()))
    t.start()
    for i in range(3):
        sleep(3)
        print(f"Main program iteration {i}")


输出

a
Background task iteration 0
Background task iteration 1
Background task iteration 2
Main program iteration 0
Background task iteration 3
Background task iteration 4
finished
b
Main program iteration 1
Main program iteration 2

ybzsozfc

ybzsozfc2#

最大的问题,沿着一些注解已经解释了你应该使用await asyncio.gather()而不是asyncio.create_task(),是asyncio.run()在主线程中运行,因此暂停执行。你不能在异步代码的同时运行同步代码,除非你使用线程。(重复:Python run non-blocking async function from sync function)。
另一个解决方法是让main也异步,如下所示:

import asyncio
import sys

async def task():
    for i in range(5):
        print(f"Background task iteration {i}")
        await asyncio.sleep(1)
    print('finished')

async def background_task():
    print("a")
    await asyncio.gather(task())
    print("b")

async def main():
    print("Main program started python", sys.version)

    for i in range(3):
        await asyncio.sleep(3)
        print(f"Main program iteration {i}")

async def runner():
    await asyncio.gather(main(), background_task())

if __name__ == "__main__":
    asyncio.run(runner())

字符串
这会产生以下结果:

Main program started python 3.11.4 (tags/v3.11.4:d2340ef, Jun  7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)]
a
Background task iteration 0
Background task iteration 1
Background task iteration 2
Main program iteration 0
Background task iteration 3
Background task iteration 4
finished
b
Main program iteration 1
Main program iteration 2

Process finished with exit code 0

相关问题