赞
踩
Python中,多进程之间的数据共享是一个复杂的主题,因为每个进程都有自己的内存空间和独立的Python解释器实例。这意味着它们不能直接共享数据,就像线程那样。但是,Python提供了几种方法来间接地实现多进程之间的数据共享。
multiprocessing
模块提供了一个Manager
对象,它可以让创建可以在多个进程之间共享的数据结构,如列表和字典。Manager
对象背后实际上是通过进程间通信(IPC)实现的。
**使用示例:**创建可以在多个进程之间共享的字典
from multiprocessing import Process, Manager
def func(d, i):
d[i] = i * i
if __name__ == '__main__':
with Manager() as manager:
d = manager.dict()
processes = [Process(target=func, args=(d, i)) for i in range(10)]
for p in processes:
p.start()
for p in processes:
p.join()
print(d)
# 执行结果
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
这两个类允许创建可以在多个进程之间共享的值和数组。
它们是基于ctypes
模块的,这意味着可以创建不同类型的数据结构(如整数、浮点数数组等)。
**使用示例:**使用共享类Value
、Array
from multiprocessing import Process, Value, Array def func(n, a): n.value = 3.1415927 for i in range(len(a)): a[i] **= 2 if __name__ == '__main__': num = Value('d', 0.0) arr = Array('i', range(10)) p = Process(target=func, args=(num, arr)) p.start() p.join() print(num.value) print(arr[:])
# 执行结果
3.1415927
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
尽管不是真正的“共享”数据,但multiprocessing.Pipe
和multiprocessing.Queue
提供了进程间通信的机制。
这些对象可以在进程之间传递数据,从而实现某种形式的数据“共享”。
使用示例:Queue
数据共享
from multiprocessing import Process, Queue
def func(q, i):
q.put('hello {} times'.format(i))
if __name__ == '__main__':
q = Queue()
plist= [Process(target=func, args=(q, i)) for i in range(3)]
for p in plist:
p.start()
p.join()
while not q.empty():
tmpVal = q.get()
print(tmpVal)
# 执行结果
hello 0 times
hello 1 times
hello 2 times
在某些情况下,可能需要直接使用操作系统的共享内存机制。可以通过multiprocessing.RawValue
和multiprocessing.RawArray
类来实现,但它们提供了更低的抽象级别,需要谨慎使用。
multiprocessing.RawValue
和 multiprocessing.RawArray
用于创建可以直接在多个进程之间共享的内存区域。
与 Manager
、Value
和 Array
不同,RawValue
和 RawArray
不提供任何锁机制,因此它们更快,但同时也需要程序员负责同步以避免数据竞争。
使用 RawValue
和 RawArray
示例:
from multiprocessing import Process, RawValue, RawArray, Lock # 使用RawValue def process_with_raw_value(value, lock): with lock: for _ in range(10000): # 假设有很多次写操作 value.value += 1 # 使用RawArray def process_with_raw_array(arr, lock): with lock: for i in range(len(arr)): arr[i] **= 2 # 对数组中的每个元素进行平方操作 if __name__ == '__main__': # 创建一个RawValue对象,初始值为0,类型为'i'(整数) lock = Lock() # 创建一个锁对象用于同步 shared_value = RawValue('i', 0) # 创建一个RawArray对象,包含5个整数元素 shared_array = RawArray('i', [1, 2, 3, 4, 5]) # 创建并启动两个进程,分别处理RawValue和RawArray p1 = Process(target=process_with_raw_value, args=(shared_value, lock)) p2 = Process(target=process_with_raw_array, args=(shared_array, lock)) p1.start() p2.start() p1.join() p2.join() # 由于RawValue和RawArray不提供同步机制,们需要使用锁来确保数据一致性 with lock: print("Shared value:", shared_value.value) # 输出共享值的最终结果 print("Shared array:", shared_array[:]) # 输出共享数组的最终结果
# 执行结果
Shared value: 10000
Shared array: [1, 4, 9, 16, 25]
注意:尽管 RawValue
和 RawArray
提供了更高的性能和更灵活的数据共享方式,但它们也更难正确使用,因为需要程序员自己处理所有的同步问题。在大多数情况下,如果不需要这么底层的控制,使用 Manager
、Value
或 Array
会更简单和安全。
由于GIL(全局解释器锁)的存在,共享数据在并发修改时可能会导致不可预知的行为。
因此,在共享数据时,请务必确保正确地同步进程,以避免数据竞争和不一致。
may the odds be ever in your favor ~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。