### 探究Python多进程编程下线程之间变量的共享问题 #### 一、问题背景与分析 在Python中,由于全局解释器锁(Global Interpreter Lock, GIL)的存在,多线程并不能实现真正的并行执行,而是通过线程调度在多个线程间切换执行。因此,在Python中实现多核CPU的并行处理时,通常采用多进程而不是多线程。然而,在多进程编程中,如何有效地在不同进程间共享变量成为了一个非常重要的课题。 在给定的例子中,作者通过一段代码展示了在没有正确使用共享变量的情况下,多个进程尝试修改同一个列表会导致最终的结果为空列表。具体代码如下: ```python from multiprocessing import Process, Manager import os manager = Manager() vip_list = [] # vip_list应为manager.list()以支持跨进程共享 def testFunc(cc): vip_list.append(cc) print('processid:', os.getpid()) if __name__ == '__main__': threads = [] for ll in range(10): t = Process(target=testFunc, args=(ll,)) t.daemon = True threads.append(t) for i in range(len(threads)): threads[i].start() for j in range(len(threads)): threads[j].join() print("------------------------") print('processid:', os.getpid()) print(vip_list) ``` 在这段代码中,每个子进程都会调用`testFunc`函数,并试图向`vip_list`添加元素。但是,由于`vip_list`是在主进程中定义的一个普通列表,所以它不会被各个子进程所共享。因此,每个子进程实际上都是在修改自己的私有列表副本,导致最终打印出的`vip_list`为空。 #### 二、Python多进程共享变量的方法 为了实现多进程之间的数据共享,可以采用以下两种方法: ##### (1)Shared memory:共享内存 通过`multiprocessing`库提供的`Value`或`Array`类,可以在进程间共享基本类型的数据,如整型、浮点型等。例如: ```python from multiprocessing import Process, Value, Array def f(n, a): n.value = 3.1415927 for i in range(len(a)): a[i] = -a[i] if __name__ == '__main__': num = Value('d', 0.0) arr = Array('i', range(10)) p = Process(target=f, args=(num, arr)) p.start() p.join() print(num.value) print(arr[:]) ``` 运行结果: ``` 3.1415927 [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] ``` 这里使用`Value`创建了一个双精度浮点类型的共享变量`num`,以及使用`Array`创建了一个整型数组`arr`。在子进程中对这些变量的修改会立即反映到其他进程。 ##### (2)Server process:管理进程 通过`Manager()`返回的对象来控制一个服务器进程,该进程持有Python对象并允许其他进程通过代理操作这些对象。`Manager()`支持的类型包括:`list`, `dict`, `Namespace`, `Lock`, `RLock`, `Semaphore`, `BoundedSemaphore`, `Condition`, `Event`, `Queue`, `Value` 和 `Array` 等。例如: ```python from multiprocessing import Process, Manager import os def testFunc(vip_list, cc): vip_list.append(cc) print('processid:', os.getpid()) if __name__ == '__main__': manager = Manager() vip_list = manager.list() # 使用Manager创建的list支持跨进程共享 processes = [] for ll in range(10): p = Process(target=testFunc, args=(vip_list, ll)) p.daemon = True processes.append(p) for p in processes: p.start() for p in processes: p.join() print("-------------") print('processid:', os.getpid()) print(vip_list) ``` 运行结果: ``` processid: 32074 processid: 32073 processid: 32072 ... ------------- processid: 32066 [3, 2, 1, 7, 5, 0, 6, 8, 4, 9] ``` 这里我们使用`Manager()`创建了一个可以被多个进程共享的列表`vip_list`,这样就可以实现多进程间的变量共享。 #### 三、多进程的数据同步问题 除了变量共享之外,多进程编程还涉及到数据同步问题。当多个进程尝试同时修改共享数据时,如果没有适当的同步机制,就可能会导致数据损坏。下面是一个简单的计数器示例: ```python from multiprocessing import Process, Value def increment(count): count.value += 1 if __name__ == '__main__': count = Value('i', 0) processes = [Process(target=increment, args=(count,)) for _ in range(10)] for p in processes: p.start() for p in processes: p.join() print(count.value) ``` 这段代码中,多个进程尝试对共享的整数值`count`进行加一操作。理论上,如果没有任何同步措施,结果应该是10。但由于存在竞争条件(race condition),实际运行结果可能不是预期的10。 为了避免这种竞争条件,可以使用锁(Lock)来保护共享资源,确保同一时间只有一个进程能够访问共享资源。例如,修改上述计数器示例中的`increment`函数: ```python from multiprocessing import Process, Value, Lock def increment(lock, count): with lock: count.value += 1 if __name__ == '__main__': count = Value('i', 0) lock = Lock() processes = [Process(target=increment, args=(lock, count)) for _ in range(10)] for p in processes: p.start() for p in processes: p.join() print(count.value) ``` 在这个例子中,我们引入了`Lock`对象来确保每次只有一个进程能够修改`count`变量,从而避免了竞争条件的发生。 总结来说,Python多进程编程中涉及的变量共享问题可以通过共享内存和管理进程两种方式解决。此外,对于需要同步访问的数据,可以使用锁等同步原语来保证数据的一致性和完整性。这些技巧对于编写高效的多进程程序至关重要。
- 粉丝: 3
- 资源: 906
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 锐捷交换机的堆叠,一个大问题
- MATLAB《结合萨克拉门托模型和遗传算法为乐安河流域建立一个水文过程预测模型》+项目源码+文档说明
- 基于人工神经网络/随机森林/LSTM的径流预测项目
- 微信小程序毕业设计-基于SSM的驾校预约小程序【代码+论文+PPT】.zip
- Aspose.Words 18.7 版本 Word转成PDF无水印
- 微信小程序毕业设计-基于Python的摄影竞赛小程序【代码+论文+PPT】.zip
- PCS7 Drive ES APL V9.1
- Python实现的文件多线程复制小工具(带用户界面)
- Java语言程序设计《学生管理系统》+项目源码+文档说明
- 2000W逆变器全套资料含源代码