如何在不阻塞的情况下发出请求(使用 asyncio)?
How to make request without blocking (using asyncio)?
我想使用 asyncio
实现以下目标:
# Each iteration of this loop MUST last only 1 second
while True:
# Make an async request
sleep(1)
但是,我看到的唯一示例使用了
的一些变体
async def my_func():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, requests.get, 'http://www.google.com')
loop = asyncio.get_event_loop()
loop.run_until_complete(my_func())
但是run_until_complete
阻塞了!在我的 while
循环的每次迭代中使用 run_until_complete
会导致循环阻塞。
我花了最后几个小时试图弄清楚如何正确地 运行 一个非阻塞任务(用 async def
定义)但没有成功。我一定遗漏了一些明显的东西,因为像这样简单的东西肯定很简单。我怎样才能实现我所描述的?
run_until_complete
运行主事件循环。它不是 "blocking" 可以这么说,它只是运行事件循环,直到你作为参数传递的协程 returns。它必须挂起,否则程序将停止或被下一条指令阻塞。
很难说出你想要实现什么,但这一段代码确实做了一些事情:
async def my_func():
loop = asyncio.get_event_loop()
while True:
res = await loop.run_in_executor(None, requests.get, 'http://www.google.com')
print(res)
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(my_func())
它会每秒在Google 主页上执行一次GET 请求,弹出一个新线程来执行每个请求。您可以通过 运行 几乎并行的多个请求说服自己它实际上是非阻塞的:
async def entrypoint():
await asyncio.wait([
get('https://www.google.com'),
get('https://www.whosebug.com'),
])
async def get(url):
loop = asyncio.get_event_loop()
while True:
res = await loop.run_in_executor(None, requests.get, url)
print(url, res)
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(entrypoint())
另一件需要注意的事情是,您每次都在单独的线程中 运行 请求。它有效,但有点像 hack。您应该使用真正的异步 HTTP 客户端,例如 aiohttp.
这是Python3.10
asyncio
是单线程执行,使用 await 将 cpu 交给其他函数,直到等待完成。
import asyncio
async def my_func(t):
print("Start my_func")
await asyncio.sleep(t) # The await yields cpu, while we wait
print("Exit my_func")
async def main():
asyncio.ensure_future(my_func(10)) # Schedules on event loop, we might want to save the returned future to later check for completion.
print("Start main")
await asyncio.sleep(1) # The await yields cpu, giving my_func chance to start.
print("running other stuff")
await asyncio.sleep(15)
print("Exit main")
if __name__ == "__main__":
asyncio.run(main()) # Starts event loop
我想使用 asyncio
实现以下目标:
# Each iteration of this loop MUST last only 1 second
while True:
# Make an async request
sleep(1)
但是,我看到的唯一示例使用了
的一些变体async def my_func():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, requests.get, 'http://www.google.com')
loop = asyncio.get_event_loop()
loop.run_until_complete(my_func())
但是run_until_complete
阻塞了!在我的 while
循环的每次迭代中使用 run_until_complete
会导致循环阻塞。
我花了最后几个小时试图弄清楚如何正确地 运行 一个非阻塞任务(用 async def
定义)但没有成功。我一定遗漏了一些明显的东西,因为像这样简单的东西肯定很简单。我怎样才能实现我所描述的?
run_until_complete
运行主事件循环。它不是 "blocking" 可以这么说,它只是运行事件循环,直到你作为参数传递的协程 returns。它必须挂起,否则程序将停止或被下一条指令阻塞。
很难说出你想要实现什么,但这一段代码确实做了一些事情:
async def my_func():
loop = asyncio.get_event_loop()
while True:
res = await loop.run_in_executor(None, requests.get, 'http://www.google.com')
print(res)
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(my_func())
它会每秒在Google 主页上执行一次GET 请求,弹出一个新线程来执行每个请求。您可以通过 运行 几乎并行的多个请求说服自己它实际上是非阻塞的:
async def entrypoint():
await asyncio.wait([
get('https://www.google.com'),
get('https://www.whosebug.com'),
])
async def get(url):
loop = asyncio.get_event_loop()
while True:
res = await loop.run_in_executor(None, requests.get, url)
print(url, res)
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(entrypoint())
另一件需要注意的事情是,您每次都在单独的线程中 运行 请求。它有效,但有点像 hack。您应该使用真正的异步 HTTP 客户端,例如 aiohttp.
这是Python3.10
asyncio
是单线程执行,使用 await 将 cpu 交给其他函数,直到等待完成。
import asyncio
async def my_func(t):
print("Start my_func")
await asyncio.sleep(t) # The await yields cpu, while we wait
print("Exit my_func")
async def main():
asyncio.ensure_future(my_func(10)) # Schedules on event loop, we might want to save the returned future to later check for completion.
print("Start main")
await asyncio.sleep(1) # The await yields cpu, giving my_func chance to start.
print("running other stuff")
await asyncio.sleep(15)
print("Exit main")
if __name__ == "__main__":
asyncio.run(main()) # Starts event loop