如何在Jupyter中使Python异步函数可调用,而不需要使用await关键字

4
我编写了一个Python库,目前它在串行中进行多个独立的HTTP请求。我想并行化这些请求,而不改变库的用户调用方式,也不需要让用户意识到在幕后异步地进行调用。该库主要面向初学者/中级Python用户,大多使用Jupyter,并且我希望它可以在不介绍陌生的"async"/"await"语义的情况下工作。
下面的示例演示了我想实现的内容,但需要使用"await"在最后一行调用代码,同时在Jupyter中可以正常工作:
import asyncio

async def first_request():
    await asyncio.sleep(2)  # Simulate request time
    return "First request response"

async def second_request():
    await asyncio.sleep(2)
    return "Second request response"

async def make_requests_in_parallel():
    """Make requests in parallel and return the responses."""
    return await asyncio.gather(first_request(), second_request())

results = await make_requests_in_parallel()  # Undesirable use of `await`

我发现了描述如何使用asyncio.run()从同步代码调用异步代码的以前的答案。在上面的Jupyter示例中,我可以将最后一行替换为以下内容,以创建一个可工作、可导入的Python模块:

def main():
    """Make results available to async-naive users""" 
    return asyncio.run(make_requests_in_parallel())

results = main()  # No `await` needed to get results -- good!

这似乎是我想要的。然而,在Jupyter中,代码会产生一个错误:

RuntimeError: asyncio.run() 无法从运行的事件循环中调用

上面同一答案的评论解释说,因为Jupyter运行自己的异步事件循环,所以没有必要(或者显然没有选项)启动另一个事件循环,因此异步代码可以“简单地”使用await来调用。然而,在我的情况下,避免使用await正是我想首先使用asyncio.run()的原因。

这似乎表明,现有的同步库不能通过任何方式在不修改其公共API以要求使用await的情况下使用asyncio内部并行化任何操作。这是真的吗?

如果是这样的话,是否有更实际的替代方案可以让我在内部函数中并行化一组请求而无需向用户介绍async/await

1个回答

3
我找到了一个很好的解决方案:nest_asyncio
安装好后,在 Jupyter 中使用该解决方案的方法如下:
import asyncio
import nest_asyncio
nest_asyncio.apply()

async def first_request():
    await asyncio.sleep(2)  # Simulate request time
    return "First request response"


async def second_request():
    await asyncio.sleep(2)
    return "Second request response"


async def make_requests_in_parallel():
    """Make requests in parallel and return the responses."""
    return await asyncio.gather(first_request(), second_request())

def main():
    """Make results available to async-naive users""" 
    return asyncio.run(make_requests_in_parallel())

results = main()  # No `await` needed to get results

谢谢分享。这绝对是我一直在寻找的最干净的解决方案,因为我需要使用jupyter作为前端。 - Frederick Zhang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接