1

在 python 2.7 中,我试图将二维数组的计算分布在所有内核上。
为此,我有两个与全局范围内的变量关联的数组,一个用于读取,一个用于写入。

import itertools as it
import multiprocessing as mp

temp_env = 20
c = 0.25
a = 0.02
arr = np.ones((100,100))
x = arr.shape[0]
y = arr.shape[1]
new_arr = np.zeros((x,y))

def calc_inside(idx):
    new_arr[idx[0],idx[1]] = (       arr[idx[0],  idx[1]  ]
                             + c * ( arr[idx[0]+1,idx[1]  ]
                                   + arr[idx[0]-1,idx[1]  ]
                                   + arr[idx[0],  idx[1]+1]
                                   + arr[idx[0],  idx[1]-1]
                                   - arr[idx[0],  idx[1]  ]*4
                                     )
                             - 2 * a
                                 * ( arr[idx[0],  idx[1]  ]
                                   - temp_env
                                     )
                               )

inputs = it.product( range( 1, x-1 ),
                     range( 1, y-1 )
                     )
p = mp.Pool()
p.map( calc_inside, inputs )

#for i in inputs:
#    calc_inside(i)

#plot arrays as surface plot to check values

假设数组有一些额外的初始化,除了arr示例性 -s 之外还有一些不同的值1,因此计算(温度的迭代计算)实际上是有意义的。

当我使用注释掉的for循环而不是Pool.map()方法时,一切正常,并且数组实际上包含值。使用该Pool()函数时,变量new_array仅保持其初始化状态(这意味着它仅包含零,因为它最初是用 初始化的)。

Q1:这是否意味着Pool()阻止写入全局变量?

Q2:有没有其他方法可以通过并行化来解决这个问题?

4

1 回答 1

0

A1:
您的代码实际上不使用任何使用语法声明的变量global <variable>。尽管如此,不要试图去尝试使用它们,更不用说去分布式处理了。

A2:
是的,并行化是可能的,但最好在花费(好吧,浪费)努力之前彻底了解这样做的成本,这永远不会证明这样做的成本是合理的。


为什么要从成本开始?

你会付给你的银行职员 2.00 美元,以换取一张 1.00 美元的钞票吗?

估计没有人会这样做。

尝试并行也是如此。

语法是“免费的”和“有前途的”,实际执行一个简单而美观的语法构造函数的语法成本不是。期待相当令人震惊的惊喜,而不是免费获得任何晚餐。


实际成本是多少?基准。基准。基准!

有用的工作
您的代码实际上只在块“内部”执行一些内存访问和一些浮点操作并退出。这些 FLOP-s在最近的 CPU 频率上占用不到几十个[ns]最大几个单位~ 。做基准测试:[us]2.6 ~ 3.4 [GHz]

from zmq import Stopwatch; aClk = Stopwatch()

temp_env = 20
c        =  0.25
a        =  0.02

aClk.start()
_ = ( 1.0
    + c * ( 1.0
          + 1.0
          + 1.0
          + 1.0
          - 1.0 * 4
            )
    - 2 * a
        * ( 1.0
          - temp_env
            )
      )
T = aClk.stop()

因此,在四核 CPU 上执行纯[SERIAL]进程不会比 a T+T+T+T(一个接一个执行)差。

         +-+-+-+--------------------------------- on CpuCore[0]
         : : : :
<start>| : : : :
       |T| : : :
       . |T| : :
       .   |T| :
       .     |T|
       .       |<stop>
       |<----->|
        = 4.T in a pure [SERIAL]-process schedule on CpuCore[0]

如果在某种形式的 now -process 执行(使用's methods )中强制执行相同数量的有用工作,可能会出于相同目的使用更多 CPU 内核,会发生什么?[CONCURRENT]multiprocessing.Pool

实际的计算阶段不会再持续T一次,对吧?为什么会这样?是的,从来没有。

                               A.......................B...............C.D Cpu[0]
<start>|                       :                       :               : :
       |<setup a subprocess[A]>|                       :               :
       .                       |                       :               
       .                       |<setup a subprocess[B]>|
       .                       | +............+........................... Cpu[!0]
       .                       | :            :        |
       .                       |T|            :        |
       .                         |<ret val(s) |        | +............+... Cpu[!0]
       .                         |   [A]->main|        | :            :
       .                                               |T|            :
       .                                                 |<ret val(s) |
       .                                                 |   [B]->main|
       .                                                                      
       .
       .                                                           ..   |<stop>
       |<--------------------------------------------------------- .. ->|
           i.e. >> 4.T ( while simplified, yet the message is clear )

间接费用 ,即您将始终为每次通话支付的成本(这确实是很多次)
子流程设置+终止成本对其进行基准测试以了解这些成本的规模)。内存访问成本(延迟,当您退出时,零缓存重用恰好有帮助)。


结语

希望视觉信息足够清晰,以便在决定将代码重新设计成分布式流程、拥有多核甚至多核结构可用的任何可实现的收益之前,总是开始计算应计成本。[CONCURRENT]

于 2017-12-04T16:29:38.050 回答