【发布时间】:2020-09-16 21:36:36
【问题描述】:
我正在尝试使用 asyncio 运行一段代码并减少整个代码的执行时间。下面是我的代码,大约需要 6 秒才能完全执行自己
普通函数调用-(方法一)
from time import time, sleep
import asyncio
def find_div(range_, divide_by):
lis_ = []
for i in range(range_):
if i % divide_by == 0:
lis_.append(i)
print("found numbers for range {}, divided by {}".format(range_, divide_by))
return lis_
if __name__ == "__main__":
start = time()
find_div(50800000, 341313)
find_div(10005200, 32110)
find_div(50000340, 31238)
print(time()-start)
上面代码的输出就是总执行时间6秒。
多线程方法-(方法 2) 在这里使用了多线程,但令人惊讶的是时间增加了
from time import time, sleep
import asyncio
import threading
def find_div(range_, divide_by):
lis_ = []
for i in range(range_):
if i % divide_by == 0:
lis_.append(i)
print("found numbers for range {}, divided by {}".format(range_, divide_by))
return lis_
if __name__ == "__main__":
start = time()
t1 = threading.Thread(target=find_div, args=(50800000, 341313))
t2 = threading.Thread(target=find_div, args=(10005200, 32110))
t3 = threading.Thread(target=find_div, args=(50000340, 31238))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(time()-start)
以上代码的输出是12 secs。
多处理方法-(方法 3)
from time import time, sleep
import asyncio
from multiprocessing import Pool
def multi_run_wrapper(args):
return find_div(*args)
def find_div(range_, divide_by):
lis_ = []
for i in range(range_):
if i % divide_by == 0:
lis_.append(i)
print("found numbers for range {}, divided by {}".format(range_, divide_by))
return lis_
if __name__ == "__main__":
start = time()
with Pool(3) as p:
p.map(multi_run_wrapper,[(50800000, 341313),(10005200, 32110),(50000340, 31238)])
print(time()-start)
多处理代码的输出为 3 secs,优于普通函数调用方法。
Asyncio 方法-(方法 4)
from time import time, sleep
import asyncio
async def find_div(range_, divide_by):
lis_ = []
for i in range(range_):
if i % divide_by == 0:
lis_.append(i)
print("found numbers for range {}, divided by {}".format(range_, divide_by))
return lis_
async def task():
tasks = [find_div(50800000, 341313),find_div(10005200, 32110),find_div(50000340, 31238)]
result = await asyncio.gather(*tasks)
print(result)
if __name__ == "__main__":
start = time()
asyncio.run(task())
print(time()-start)
上面的代码也需要大约 6 秒,这与 Approach 1 的正常执行函数调用相同。
问题-
为什么我的 Asyncio 方法没有按预期工作并减少了总时间?
代码有什么问题?
【问题讨论】:
-
我认为这只是示例代码?因为有一种比检查范围内每个数字的模数更有效的方法来获取一个数字的所有倍数的列表
-
您的“异步”函数不会等待任何内容,因此它们甚至不会尝试切换执行,它们只是作为普通同步代码执行。如果您在循环中添加类似
await asyncio.sleep(0)的内容,它们将开始产生并同时执行。请注意,您不会以这种方式获得加速,甚至可能会证明异步是所有测试变体中最慢的。正如答案中所解释的,这是因为异步执行是为并行等待而设计的,而不是为并行执行而设计的,而且您的代码显然受 CPU 限制。 -
如果你想在你的程序中使用 asyncio 来处理其他事情(比如网络通信),但是有 CPU 绑定的代码应该在多个内核上执行,你可以使用 @ 结合 multiprocessing 和 asyncio 987654321@.
-
MaxNoe,是的,这只是一个示例/示例代码。 user4815162342,谢谢这个链接看起来很有用,我去看看。
标签: python multithreading async-await multiprocessing python-asyncio