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