如何使用多个线程并行地增加相同的变量,以便将所花费的总时间减少到原始同步进程所花费的时间的倍数?
的例子:
num = 0
def incrementer():
for i in range(100):
global num
num += 1
for i in range(100):
th=Thread(target=incrementer)
th.start()
num
上面的代码确实给出了预期的结果(10000),但是所花费的时间比同步方法要长得多:
In [114]: %%timeit
...: num = 0
...: def incrementer():
...: for i in range(100):
...: global num
...: num += 1
...: for i in range(100):
...: th=Thread(target=incrementer)
...: th.start()
25.3 ms ± 2.27 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [113]: %%timeit
...: num = 0
...: for i in range(10000):
...: num += 1
596 µs ± 84.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
我期望多线程方法所花费的时间是同步方法所花费时间的1%…
对于n个线程,我怎样才能使异步方法只花费同步方法所花费时间的n倍,或者这显然是不可能的?
多线程性能提升并不像你想象的那样线性。
假设您有一个4核CPU (nc=4),从单线程(t=1)到4线程(t=4)应该会显示总体计算时间的减少。如果你有一个4核CPU,你可能期望减少75%的计算时间,但在现实世界中,仍然需要做一些工作来保持操作系统的运行。
拥有比物理内核数量更多的线程(t>nc)最多可以提供与匹配这些值(t=nc)相同的性能,但在现实世界中,使用t>>nc管理资源实际上可能会运行得慢一点。
接下来,你的方法是使用一个计数器,由所有线程更新,这增加了复杂性,因为你需要一个互斥锁/信号量等。为了确保计数器更新在多方读写的情况下按预期运行——多方越多,执行起来就越困难,而且,您猜对了,又会对性能造成影响。
我建议将你的问题空间划分为线程的数量(t=nc,如果你正在阅读上面的内容),这样(例如)threadA
进程0-24
,threadB: 25-49
,threadC 50-74
和threadD: 75-99
-这样它们就不需要相互通信,因为每个线程都在处理自己的问题空间。
tl;博士:
- 当多线程时,超越
t=nc
几乎没有任何优势,但在功能上,你甚至可能想要停止在t=(nc-1)
,为你的操作系统/等留下一些CPU时间。 - 线程同步需要仔细完成;在将作业发送到线程之前,尝试将饼切成
t
块。