Python并行(parallel)之谈
简介
可以先看看并发Concurrent与并行Parallel的区别
在谈并行前,头脑中总会浮出多线程、多进程、线程/进程同步、线程/进程通信等词语。
那为什么需要同步、通信,它们之间的作用是怎样的呢?
通信,稍微好理解,就是多线程/进程之间相互通话,比如我打电话呼叫你,我说什么,你答什么,或者我说,你只听。它着重于数据的传递
同步,其实是相对于共享内存而言,比如,我们在同一时刻同一个地方修改了共享对象的数据,这样就会导致数据的篡改,得不到理想中的结果,这时就需要同步。它的基础是基于共享同一个对象而言。
现在软件世界中,存在着很多模式和框架,比如设计模式,MVC框架,那么并行编程是否也存在某些模式呢?
常用的四种并行模式
- 共享内存模式(The shared memory model)
- 多线程模式(The multithread model)
- 分布式内存/消息传递模式(The distributed memory/message passing model)
- 数据并行模式(The data parallel model)
现在我们再来看看线程/进程同步,它们是不是基于共享内存模式;线程/进程通信对应着消息传递模式。
说明一点:数据并行,是将数据分割成多组相互独立的数据处理。
设计并发程序的四个阶段(PCAM设计方法学):
-
划分(Partitioning):分解成小的任务,开拓并发性
-
通讯(Communication):确定诸任务间的数据交换,监测划分的合理性;
-
组合(Agglomeration):依据任务的局部性,组合成更大的任务;
-
映射(Mapping):将每个任务分配到处理器上,提高算法的性能。
案例演示
该案例,采用Python多进程实现。进程间通信在官网的例子叫做Exchanging objects between processes,进程同步在官网的例子叫做Synchronization between processes 以及 Sharing state between processes。
设计并发程序。
首先,任务分解:1个进程专门存储数据,多个进程取数据并进行计算。
其次,进程通信:采取queue队列供存取进程通信。
最后,组合:多个进程计算后的数据,怎么组合在一起呢?采取多进程的共享内存数据Value,如果是多个进程对共享数据操作,则需进行同步。
1 import multiprocessing 2 3 def make_data(queue, num, work_nums): 4 for i in range(num): 5 queue.put(i) 6 for i in range(work_nums): 7 queue.put(None) 8 9 def handle_data(queue, share_value, lock): 10 while True: 11 data = queue.get() 12 if data is None: 13 break 14 lock.acquire() 15 share_value.value = share_value.value + data 16 lock.release() 17 18 if __name__ == "__main__": 19 queue = multiprocessing.Queue() # 进程间通信所用 20 share_value = multiprocessing.Value("i", 0) # 进程间共享所用 21 lock = multiprocessing.Lock() # 进程间共享内存时,采用锁同步机制 22 num = 10000 # 23 work_nums = 5 # work进程个数 24 sub_process = [] # 处理数据进程集合 25 26 master_process = multiprocessing.Process(target=make_data, args=(queue, num, work_nums, )) # 生成数据进程 27 for i in range(work_nums): 28 sub_process1 = multiprocessing.Process(target=handle_data, args=(queue, share_value, lock,)) 29 sub_process.append(sub_process1) 30 31 master_process.start() 32 for p in sub_process: 33 p.start() 34 35 master_process.join() 36 for p in sub_process: 37 p.join() 38 39 # 结果对比 40 result = 0 41 for i in range(num): 42 result = result + i 43 print("result should be " + str(result)) 44 print("fact is " + str(share_value.value))
输出结果:
result should be 49995000
fact is 49995000
参考:
1、《Python Parallel Programming Cookbook》