运行 IOLoop.current() 中的函数。run_in_executor?
Running function in IOLoop.current().run_in_executor?
我看了下面的代码
async def f():
sc_client = session.client("ec2")
for id in ids:
await IOLoop.current().run_in_executor(None, lambda: client.terminate(id))
它与以下代码相比如何? client.terminate
会是 运行 并行吗?但是每次执行都在等待?
for id in ids:
client.terminate(id)
Will client.terminate be run in parallel?
不,它仍然是 运行 顺序。
IOLoop.current().run_in_executor
将 运行 blocking function
在一个单独的线程中 returns 一个 asyncio.Future
,而 await
将等到 Future
调用 client.terminate
完成,然后循环继续。
你给出的两个选项的区别是:
如果程序有其他协程到运行,使用第一个选项,另一个协程不会阻塞,而使用第二个选项,另一个协程将阻塞等待你的for循环完成。
举个例子让大家明白(这里为了简单起见,会用loop.run_in_executor
来模拟IOLoop.current().run_in_executor
):
test.py:
import asyncio
import concurrent.futures
import time
def client_terminate(id):
print(f"start terminate {id}")
time.sleep(5)
print(f"end terminate {id}")
async def f():
loop = asyncio.get_running_loop()
for id in range(2):
with concurrent.futures.ThreadPoolExecutor() as pool:
await loop.run_in_executor(pool, client_terminate, id)
# client_terminate(id)
async def f2():
await asyncio.sleep(1)
print("other task")
async def main():
await asyncio.gather(*[f(), f2()])
asyncio.run(main())
运行输出为:
$ python3 test.py
start terminate 0
other task
end terminate 0
start terminate 1
end terminate 1
你可以看到 for 循环中的 two client_terminate
仍然按顺序 运行s,BUT,函数 f2
打印 other task
在它们之间注入,它不会阻塞 asyncio scheduler
调度 f2
.
补充:
如果将await loop.run_in_executor
& threadpool
相关的2行注释掉,直接调用client_terminate(id)
,输出为:
$ python3 test.py
start terminate 0
end terminate 0
start terminate 1
end terminate 1
other task
意味着如果你不将 blocking function
包裹在 Future
中,other task
将不得不等待你的 for loop
完成,这会浪费 CPU.
我看了下面的代码
async def f():
sc_client = session.client("ec2")
for id in ids:
await IOLoop.current().run_in_executor(None, lambda: client.terminate(id))
它与以下代码相比如何? client.terminate
会是 运行 并行吗?但是每次执行都在等待?
for id in ids:
client.terminate(id)
Will client.terminate be run in parallel?
不,它仍然是 运行 顺序。
IOLoop.current().run_in_executor
将 运行 blocking function
在一个单独的线程中 returns 一个 asyncio.Future
,而 await
将等到 Future
调用 client.terminate
完成,然后循环继续。
你给出的两个选项的区别是:
如果程序有其他协程到运行,使用第一个选项,另一个协程不会阻塞,而使用第二个选项,另一个协程将阻塞等待你的for循环完成。
举个例子让大家明白(这里为了简单起见,会用loop.run_in_executor
来模拟IOLoop.current().run_in_executor
):
test.py:
import asyncio
import concurrent.futures
import time
def client_terminate(id):
print(f"start terminate {id}")
time.sleep(5)
print(f"end terminate {id}")
async def f():
loop = asyncio.get_running_loop()
for id in range(2):
with concurrent.futures.ThreadPoolExecutor() as pool:
await loop.run_in_executor(pool, client_terminate, id)
# client_terminate(id)
async def f2():
await asyncio.sleep(1)
print("other task")
async def main():
await asyncio.gather(*[f(), f2()])
asyncio.run(main())
运行输出为:
$ python3 test.py
start terminate 0
other task
end terminate 0
start terminate 1
end terminate 1
你可以看到 for 循环中的 two client_terminate
仍然按顺序 运行s,BUT,函数 f2
打印 other task
在它们之间注入,它不会阻塞 asyncio scheduler
调度 f2
.
补充:
如果将await loop.run_in_executor
& threadpool
相关的2行注释掉,直接调用client_terminate(id)
,输出为:
$ python3 test.py
start terminate 0
end terminate 0
start terminate 1
end terminate 1
other task
意味着如果你不将 blocking function
包裹在 Future
中,other task
将不得不等待你的 for loop
完成,这会浪费 CPU.