繁体   English   中英

为什么顺序代码比多线程代码快?

[英]Why is the sequential code faster than the multithreaded code?

为什么顺序代码比多线程代码运行得更快?

import time
import math
import threading

def run(i):
    i = i * math.pi
    return i**2

def run2(i, j, l):
    for x in range(i, j):
        l.append((x*math.pi)**2)

if __name__ == "__main__":
    tm = time.time()
    # Sequential
    res = [run(i) for i in range(20000)]
    print(time.time() - tm)
   
    tm = time.time()
    # Multithreaded
    n = 24 # Number of threads
    ans = []
    t = 20000
    for i in range(n - 1):
        ans.append([])
        tp = threading.Thread(target=run2, args=(round(t//n*i), round(t//n*(i+1)), ans[len(ans) - 1]))
        tp.start()
    ans.append([])
    tp = threading.Thread(target=run2, args=(round(t//n*n), t, ans[len(ans) - 1]))
    tp.start()
    
    print(time.time() - tm)

似乎对于非密集型任务,顺序更快。 任何想法为什么以及如何加速多线程版本?

由于 GIL,python 解释器在任何给定时间都不能运行多个 python 代码。

但是, appending ,您要appending到列表中。

>>> import timeit
>>> def appending():
...     output = []
...     for i in range(1000000):
...         output.append(i)
...     return output
... 
>>> def gen_exp():
...     return [i for i in range(1000000)]

>>> print(f"{timeit.timeit(appending, number=100):.2}")
8.1

>>> print(f"{timeit.timeit(gen_exp, number=100):.2}")
5.2

追加到list这种缓慢性质在readline/readlines性能差异上得到了最好的展示。

如果没有这些,通常时间基准将被简化如下。

import math
import timeit
from concurrent import futures
import multiprocessing


def run(i):
    i = i * math.pi
    return i ** 2


def wrapper_sequential():
    return [run(i) for i in range(20000)]


def wrapper_thread_pool():
    with futures.ThreadPoolExecutor(max_workers=10) as exc:
        fut = [exc.submit(run, i) for i in range(20000)]
        output = [f.result() for f in fut]

    return output


def wrapper_multiprocess():
    with multiprocessing.Pool(10) as pool:
        output = pool.map(run, (i for i in range(20000)))

    return output


if __name__ == '__main__':
    print(f"Thr: {timeit.timeit(wrapper_thread_pool, number=10):.4}")
    print(f"Seq: {timeit.timeit(wrapper_sequential, number=10):.4}")
    print(f"Mlt: {timeit.timeit(wrapper_multiprocess, number=10):.4}")

Thr: 5.146
Seq: 0.05411
Mlt: 4.055

创建thread成本是不值得的,因为 GIL 在任何给定时刻只允许一个 python 解释器单个 python 代码。

对于Multiprocessing ,由于 python 解释器没有直接的方式通过进程进行通信,因此内部使用pickle来序列化进程间通信的数据 - 这是开销。

如果计算量足够大, Multiprocessing最终将克服该开销并开始领先于顺序处理,但thread永远不会。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM