运行并等待异步函数从一个同步的使用Python Python Python Python

1aaf6o9v  于 4个月前  发布在  Python
关注(0)|答案(4)|浏览(149)

在我的代码中,我有一个带有属性的类,它偶尔需要运行异步代码。有时我需要从异步函数访问属性,有时从同步函数访问-这就是为什么我不希望我的属性是异步的。此外,我有一种印象,异步属性通常是代码的味道。如果我错了,请纠正我。
我在从synchronous属性执行异步方法并阻止进一步执行直到异步方法完成时遇到了问题。
下面是一个示例代码:

import asyncio

async def main():
    print('entering main')
    synchronous_property()
    print('exiting main')

def synchronous_property():
    print('entering synchronous_property')
    loop = asyncio.get_event_loop()
    try:
        # this will raise an exception, so I catch it and ignore
        loop.run_until_complete(asynchronous())
    except RuntimeError:
        pass
    print('exiting synchronous_property')

async def asynchronous():
    print('entering asynchronous')
    print('exiting asynchronous')

asyncio.run(main())

字符串
其输出:

entering main
entering synchronous_property
exiting synchronous_property
exiting main
entering asynchronous
exiting asynchronous


首先,RuntimeError捕获似乎是错误的,但如果我不这样做,我会得到RuntimeError: This event loop is already running异常。
第二,asynchronous()函数是最后执行的,在同步函数完成之后。我想用异步方法对数据集做一些处理,所以我需要等待它完成。如果我在调用synchronous_property()之后添加await asyncio.sleep(0),它会在main()完成之前调用asynchronous(),但这对我没有帮助。我需要在synchronous_property()完成之前运行asynchronous()
我错过了什么?我运行的是Python 3.7。

busg9geu

busg9geu1#

Asyncio确实坚持不允许嵌套事件循环,by design。然而,你总是可以在不同的线程中运行另一个事件循环。这里有一个变体,它使用线程池来避免每次都创建一个新线程:

import asyncio, concurrent.futures

async def main():
    print('entering main')
    synchronous_property()
    print('exiting main')

pool = concurrent.futures.ThreadPoolExecutor()

def synchronous_property():
    print('entering synchronous_property')
    result = pool.submit(asyncio.run, asynchronous()).result()
    print('exiting synchronous_property', result)

async def asynchronous():
    print('entering asynchronous')
    await asyncio.sleep(1)
    print('exiting asynchronous')
    return 42

asyncio.run(main())

字符串
这段代码在每个sync→ sync_c边界上创建一个新的事件循环,所以如果你经常这样做,不要期望高性能。可以通过使用asyncio.new_event_loop为每个线程只创建一个事件循环,并将其缓存在线程本地变量中来改进它。

mhd8tkvw

mhd8tkvw2#

最简单的方法是使用现有的“wheel”,如asgiref.async_to_sync

from asgiref.sync import async_to_sync

字符串
然后:

async_to_sync(main)()


一般而言:

async_to_sync(<your_async_func>)(<.. arguments for async function ..>)


这是一个调用者类,它将只在具有事件循环的线程上工作的可等待对象转换为在子线程中工作的同步可调用对象。
如果调用堆栈包含一个循环,代码将在那里运行。否则,代码将在新线程的新循环中运行。
无论采用哪种方式,该线程都会暂停并等待运行使用SyncToAsync从调用堆栈的更底层调用的任何thread_sensitive代码,然后在SyncToAsync任务返回后退出。

wgx48brx

wgx48brx3#

问题似乎有问题,我重申问题:如何在线程之间通信(不包含任何同步进程,因此被视为同步)和一个同步进程(在某些事件循环中运行)。一种方法是使用两个同步进程。同步进程将其请求/参数放入QtoAsync,并等待QtoSync。同步进程读取QtoAsync而无需等待,如果找到请求/参数,则执行请求,并将结果放入QtoSync。

import queue
QtoAsync = queue.Queue()
QtoSync = queue.Queue()
...

async def asyncProc():
    while True:
        try:
            data=QtoAsync.get_nowait()
            result = await <the async that you wish to execute>
            QtoAsync.put(result) #This can block if queue is full. you can use put_nowait and handle the exception.
        except queue.Empty:
            await asyncio.sleep(0.001) #put a nominal delay forcing this to wait in event loop
....
#start the sync process in a different thread here..
asyncio.run(main()) #main invokes the async tasks including the asyncProc

The sync thread puts it request to async using:
req = <the async that you wish to execute>
QtoAsync.put(req)
result = QtoSync.get()

字符串
这个应该能用
上述问题的问题:1.当使用asyncio.run(或类似的)执行块启动Pencil c进程时,直到Pencil c进程完成。在调用Pencil cio.run之前,必须显式启动单独的同步线程2.一般情况下,Pencil cio进程依赖于该循环中的其他Pencil cio进程。因此,不允许直接从另一个线程调用Pencil c进程。交互应该与事件循环交互,使用两个队列是一种方法。

odopli94

odopli944#

我想调用同步执行并阻止它的执行
只需将sync函数设置为synchronc并等待异步函数。异步函数就像普通函数一样,您可以将任何代码放入其中。如果您仍然有问题,请使用您尝试运行的实际代码修改您的问题。

import asyncio

async def main():
    print('entering main')
    await synchronous_property()
    print('exiting main')

async def synchronous_property():
    print('entering synchronous_property')

    await asynchronous()

    # Do whatever sync stuff you want who cares

    print('exiting synchronous_property')

async def asynchronous():
    print('entering asynchronous')
    print('exiting asynchronous')

asyncio.run(main())

字符串

相关问题