标签: python-asyncio

异步函数完成后Python调用回调

我试图在异步函数运行完成后调用回调

这是我想做的一个例子:

import asyncio

async def asyncfunction():
    print('Hello')
    await asyncio.sleep(10)
    print('World')
    return 10

def callback(n):
    print(f'The async function returned: {n}')

loop = asyncio.get_event_loop()

# Will block the print until everything is done
callback(loop.run_until_complete(asyncfunction()))
print('Hey')
Run Code Online (Sandbox Code Playgroud)

这是它的作用:

Hello
World
The async function returned: 10
Hey
Run Code Online (Sandbox Code Playgroud)

这就是我想要它做的
编辑:“嘿”的位置并不重要,只要它不必等待异步函数完成即可

Hello
Hey
World
The async function returned: 10
Run Code Online (Sandbox Code Playgroud)

编辑:经过一些测试,我找到了一种可以实现我想要的功能的方法,尽管我不知道这是否是最好的方法

Hello
World
The async function returned: 10
Hey
Run Code Online (Sandbox Code Playgroud)

python python-asyncio

5
推荐指数
2
解决办法
2万
查看次数

是否可以让装饰器在 asyncio 执行器中运行阻塞函数?

我可能需要帮助更好地表达这个问题。我正在通过 python3.7 和一个类(称为Worker())编写一个异步 api 接口。Worker有一些我想使用运行的阻塞方法loop.run_in_executor()。

我想构建一个装饰器,我可以async在所有非方法之上添加Worker,但我不断遇到问题。

有人告诉我我需要await wraps()在下面的装饰器中:

def run_method_in_executor(func, *, loop=None):
    async def wraps(*args):
        _loop = loop if loop is not None else asyncio.get_event_loop()
        return await _loop.run_in_executor(executor=None, func=func, *args)
    return wraps
Run Code Online (Sandbox Code Playgroud)

这会抛出: RuntimeWarning: coroutine 'run_method_in_executor.<locals>.wraps' was never awaited

我不知道如何正确地执行,await wraps()因为包含函数和修饰函数不是异步的。不确定这是由于误解asyncio还是装饰器的误解。

任何帮助(或帮助澄清)将不胜感激!

python asynchronous decorator python-3.x python-asyncio

5
推荐指数
2
解决办法
1855
查看次数

Python 协程的回溯

假设我有以下代码:

from types import coroutine

@coroutine
def stop():
    yield 1

async def test2():
    await stop()

async def test1():
    await test2()
    await test2() # Here
    await test2()

coro = test1()
coro.send(None)
coro.send(None)
Run Code Online (Sandbox Code Playgroud)

如何获得当前协程状态的回溯(回溯对象),即标有注释的行,而不人为地抛出不需要的异常?

coroutine python-3.x python-asyncio

5
推荐指数
1
解决办法
2487
查看次数

立即从同步代码执行异步回调

问题

我有一个库,目前没有异步支持,需要从异步代码调用。handler异步代码通过处理程序(下面代码中的函数)调用库。当处理程序执行时,库会定期调用回调 ( callback_wrapper) 来报告进度。

同步处理程序的执行顺序是为了ThreadPoolExecutor使主事件循环能够在处理程序运行时处理更多事件。

发生的情况是同步回调立即执行,但异步回调仅在主处理程序执行后执行。期望的结果是立即执行异步回调。

我猜事件循环在run_in_executor调用时被阻止,但我不知道如何解决这个问题。

代码

import asyncio
import time
from concurrent.futures.thread import ThreadPoolExecutor

loop = asyncio.get_event_loop()


def handler():
    print('handler started')
    callback_wrapper()
    time.sleep(1)
    print('handler stopped')


async def callback():
    print('callback')


def callback_wrapper():
    print('callback wrapper started')
    asyncio.ensure_future(callback(), loop=loop)
    print('callback wrapper stopped')


async def main():
    handler()


with ThreadPoolExecutor() as pool:
    async def thread_handler():
        await loop.run_in_executor(pool, handler)


    loop.run_until_complete(main())

Run Code Online (Sandbox Code Playgroud)

输出

handler started
callback wrapper started
callback wrapper stopped
handler stopped
callback
Run Code Online (Sandbox Code Playgroud)

所需输出

handler started
callback …
Run Code Online (Sandbox Code Playgroud)

python threadpoolexecutor python-asyncio python-3.7

5
推荐指数
1
解决办法
1719
查看次数

如何在python36中获取当前正在运行的EventLoop?

我知道在python37中我们有一个新的api asyncio.get_running_loop(),它很容易使用,让我们在调用协程时不需要显式地传递eventloop。

我想知道我们是否可以使用任何方法在 python36 中获得相同的效果?

# which allows us coding conveniently with this api:
import asyncio

async def test():
    print("hello world !")

async def main():
    loop = asyncio.get_running_loop()
    loop.create_task(test())

asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)

python-asyncio python-3.6

5
推荐指数
1
解决办法
4007
查看次数

如何使用 aiobotocore 从 s3 进行多个并发下载?

我正在尝试使用 aiobotocore 和 boto 的 s3 方法从 s3 中提取多个文件get_object。我想让请求并发并最后将结果收集到一个数组中。我将如何构建我的代码?我在网上找不到任何如何执行此操作的示例。任何帮助将非常感激。

python-asyncio botocore boto3

5
推荐指数
0
解决办法
1570
查看次数

为什么此示例代码中需要 run_forever ?

在 python asyncio websockets 库中,该示例调用run_forever(). 为什么需要这样做?

不应该run_until_complete()阻止并运行 websockets 循环吗?

#!/usr/bin/env python

# WS server example

import asyncio
import websockets

async def hello(websocket, path):
    name = await websocket.recv()
    print(f"< {name}")

    greeting = f"Hello {name}!"

    await websocket.send(greeting)
    print(f"> {greeting}")

start_server = websockets.serve(hello, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
# if you comment out the above line, this doesn't work, i.e., the server
# doesn't actually block waiting for data...
Run Code Online (Sandbox Code Playgroud)

如果我注释掉 run_forever(),程序会立即结束。

start_server是图书馆返回的等待对象。为什么不足以run_until_complete导致它阻塞/等待hello()?

websocket python-3.x python-asyncio

5
推荐指数
1
解决办法
2153
查看次数

asyncio.run_coroutine_threadsafe 的未来永远挂起?

作为我上一个关于从同步函数调用异步函数的问题的后续,我发现了asyncio.run_coroutine_threadsafe。

从纸面上看,这看起来很理想。根据StackOverflow 问题中的评论,这看起来很理想。我可以创建一个新线程,获取对原始事件循环的引用,并安排异步函数在原始事件循环内运行,同时仅阻塞新线程。

class _AsyncBridge:
    def call_async_method(self, function, *args, **kwargs):
        print(f"call_async_method {threading.get_ident()}")
        event_loop = asyncio.get_event_loop()
        thread_pool = ThreadPoolExecutor()
        return thread_pool.submit(asyncio.run, self._async_wrapper(event_loop, function, *args, **kwargs)).result()

    async def _async_wrapper(self, event_loop, function, *args, **kwargs):
        print(f"async_wrapper {threading.get_ident()}")
        future = asyncio.run_coroutine_threadsafe(function(*args, **kwargs), event_loop)
        return future.result()
Run Code Online (Sandbox Code Playgroud)

这不会出错,但也不会返回。期货只是挂起,异步调用永远不会被命中。call_async_method我是否在、_async_wrapper或两者中使用 Future 似乎并不重要;无论我在哪里使用 Future,它都会挂起。

我尝试将调用run_coroutine_threadsafe直接放入主事件循环中:

event_loop = asyncio.get_event_loop()
future = asyncio.run_coroutine_threadsafe(cls._do_work_async(arg1, arg2, arg3), event_loop)
return_value = future.result()
Run Code Online (Sandbox Code Playgroud)

未来也悬在这里。

我尝试使用此处LoopExecutor定义的类,这似乎完全满足了我的需求。

event_loop = asyncio.get_event_loop()
loop_executor …
Run Code Online (Sandbox Code Playgroud)

python python-3.x python-asyncio

5
推荐指数
1
解决办法
5244
查看次数

Python 协程不与 time.sleep() 同时运行?

我正在尝试遵循https://docs.python.org/3/library/asyncio-task.html#coroutines中的示例;这是同时运行两个say_after协程的代码片段:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    # time.sleep(delay)
    print(what)


async def main():
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))


    print(f"Started at {time.strftime('%X')}")

    await task1
    await task2

    print(f"Finished at {time.strftime('%X')}")


if __name__ == "__main__":
    asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)

如果我运行这个,我会发现开始和结束相隔两秒:

Started at 12:59:35
hello
world
Finished at 12:59:37
Run Code Online (Sandbox Code Playgroud)

但是,如果我替换await asyncio.sleep(delay)为time.sleep(delay)(上面代码片段中的注释行),我会发现它们相隔三秒,因此基本上是同步运行的:

Started at 13:00:53
hello
world
Finished at 13:00:56
Run Code Online (Sandbox Code Playgroud)

我不太明白这一点;即使任务本身包含同步代码,并行运行的并发任务的意义不是吗?为什么这个例子不再适用time.sleep()于而不是asyncio.sleep()?

python coroutine async-await python-asyncio

5
推荐指数
1
解决办法
1295
查看次数

如何运行协程而不等待它?

我有一个非异步函数,如下所示:

def do_stuff(on_finished):
    result = # complicated calculations here
    on_finished(result)
Run Code Online (Sandbox Code Playgroud)

我传入的回调看起来或多或少像这样:

async def on_finished(self, result):
    response = await post_over_http(result)
    self.last_status = response.status 
Run Code Online (Sandbox Code Playgroud)

当我打电话时do_stuff,我想要发生的是这样的:

  1. do_stuff执行并调用on_finished
  2. on_finished执行,通过 HTTP 发布结果,然后立即返回。
  3. do_stuff现在立即返回。
  4. 随后,HTTP 响应返回,执行返回到 的第二行on_finished。

重要的是,我不希望 do_stuff 是 async。出于架构原因,我希望do_stuff与网络代码的异步性质隔离,因此我不想仅仅因为使用它的某些代码是异步的而将其设为异步。

在 JavaScript 中这不会有问题 - 基本上将上述代码直接转录为 JavaScript,我将获得所需的行为。onFinished将返回一个 Promise,它doStuff不会等待并立即返回,但是当 Promise 稍后解析时,第二行运行onFinished。这在Python中可能吗?我不确定如何实现它。通过上面的代码,我想我只是在最后一行创建了一个协程,do_stuff但从未调用它。

python python-asyncio

5
推荐指数
1
解决办法
7339
查看次数