一个计算数字平方并存储结果的简单程序:
import time
from joblib import Parallel, delayed
import multiprocessing
array1 = [ 0 for i in range(100000) ]
def myfun(i):
return i**2
#### Simple loop ####
start_time = time.time()
for i in range(100000):
array1[i]=i**2
print( "Time for simple loop --- %s seconds ---" % ( time.time()
- start_time
)
)
#### Parallelized loop ####
start_time = time.time()
results = Parallel( n_jobs = -1,
verbose = 0,
backend = "threading"
)(
map( delayed( myfun ),
range( 100000 )
)
)
print( "Time for parallelized method --- %s seconds ---" % ( time.time()
- start_time
)
)
#### Output ####
# >>> ( executing file "Test_vr20.py" )
# Time for simple loop --- 0.015599966049194336 seconds ---
# Time for parallelized method --- 7.763299942016602 seconds ---
这可能是两个选项的数组处理不同吗?我的实际程序会有更复杂的东西,但是这是我需要并行化的计算,尽可能简单,但不会得到这样的结果。
System Model: HP ProBook 640 G2, Windows 7,
IDLE for Python System Type: x64-based PC Processor:
Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz,
2401 MHz,
2 Core(s),
4 Logical Processor(s)
我喜欢Python。
我祈祷教育工作者更好地解释工具的成本,否则我们会迷失在这些想要得到的
[PARALLEL]
-时间表中。
No.0:通过大量简化,Python 有意使用 GIL 来
[SERIAL]
访问变量,从而避免 [CONCURRENT]
修改带来的任何潜在冲突 - 支付这些 GIL 的附加成本-加时赛中的踢踏舞[PARALLEL]
-代码执行比“只是”困难得多-[CONCURRENT]
(阅读更多)[SERIAL]
-如果试图将工作分配给[CONCURRENT]
-工人,流程必须支付额外费用
No.3:如果一个进程进行工人间通信,则每次数据交换都会付出巨大的额外成本
否。4:如果硬件用于 [CONCURRENT]
进程的资源很少,结果会进一步变得更糟
效率在于更好地使用芯片,而不是将语法构造函数推入合法的领域,但它们的性能会对测试中的实验端到端速度产生不利影响:
您支付大约
8 ~ 11 [ms]
只是为了迭代地组装一个空的 array1
>>> from zmq import Stopwatch
>>> aClk = Stopwatch()
>>> aClk.start();array1 = [ 0 for i in xrange( 100000 ) ];aClk.stop()
9751L
10146L
10625L
9942L
10346L
9359L
10473L
9171L
8328L
(
Stopwatch().stop()
方法从 [us]
产生
.start()
)>>> import numpy as np
>>>
>>> aClk.start();arrayNP = np.zeros( 100000 );aClk.stop()
15L
22L
21L
23L
19L
22L
>>> aClk.start();arrayNP = np.zeros( 100000, dtype = np.int );aClk.stop()
43L
47L
42L
44L
47L
因此,使用正确的工具只是性能故事的开始:>>> def test_SERIAL_python( nLOOPs = 100000 ):
... aClk.start()
... for i in xrange( nLOOPs ): # py3 range() ~ xrange() in py27
... array1[i] = i**2 # your loop-code
... _ = aClk.stop()
... return _
虽然简单的[SERIAL]
~ 70 [ms]
:
>>> test_SERIAL_python( nLOOPs = 100000 )
70318L
69211L
77825L
70943L
74834L
73079L
使用更合适/合适的工具仅需约 0.2 [ms]>>> aClk.start();arrayNP[:] = arrayNP[:]**2;aClk.stop()
189L
171L
173L
187L
183L
188L
193L
还有另一个小故障,又名就地操作方式:
>>> aClk.start();arrayNP[:] *=arrayNP[:];aClk.stop()
138L
139L
136L
137L
136L
136L
137L
仅使用适当的工具即可提高〜+514x速度关于
并行化-(不惜一切代价),而在于使用基于专业知识的方法,以最少的成本实现最大的加速。
(加速0.9甚至<< 1.0 are so often reported here, on Stack Overflow, that you need not feel lost or alone in this sort of surprise ).
核心数量很重要。
但缓存大小 + NUMA 不规则性的影响远不止于此。
智能、矢量化、HPC 固化、无 GIL 库很重要
( numpy
作为一个开销严格阿姆达尔定律(重新)制定解释,为什么甚至许多-N
-CPU并行代码执行可能(而且确实经常如此)受到速度的影响-上升<< 1.0 阿姆达尔定律加速的开销严格制定
S
[PAR]-
设置+
[PAR]-
终止开销,明确:
1
S = __________________________; where s, ( 1 - s ), N were defined above
( 1 - s ) pSO:= [PAR]-Setup-Overhead add-on
s + pSO + _________ + pTO pTO:= [PAR]-Terminate-Overhead add-on
N
(用于 2D 可视化效果的交互式动画工具这些性能限制被引用此处)
threading
的文档:
如果您知道您正在调用的函数是基于已编译的函数 释放 Python 全局解释器锁 (GIL) 的扩展 在其大部分计算过程中...
仅当问题是在这种情况下,你不知道这一点。 Python 本身只允许一个线程同时运行(Python 解释器每次执行 Python 操作时都会锁定 GIL)。
threading
并且该扩展释放了 GIL
时,
myfun()
才会有用。
Parallel
代码慢得令人尴尬,因为你需要做大量的工作来创建多个线程 - 然后你一次只能执行一个线程。
如果您使用
multiprocessing
后端,那么您必须将输入数据复制到四个或八个进程(每个核心一个)中的每一个中,在每个进程中进行处理,然后将输出数据复制回来。复制会很慢,但如果处理比仅仅计算平方更复杂一点,那么可能是值得的。测量一下看看。