更新时间:2023年04月04日10时53分 来源:传智教育 浏览次数:
Python中的multiprocessing模块提供了一种创建和管理进程的方式,使得可以利用多个CPU来加速程序运行。在这里,我会详细介绍Python中的多进程编程,包括以下内容:
一.多进程概念
二.multiprocessing模块介绍
三.进程池
四.进程通信
五.multiprocessing的一些注意事项
多进程是指在同一时间内,同时执行多个程序或多个部分的程序。每个进程都拥有自己的地址空间、内存、文件描述符和其他系统资源。多进程的好处在于可以使程序并行执行,从而提高程序的运行效率。
multiprocessing模块提供了一个Process类,可以用来创建和管理进程。下面是一个简单的示例:
import multiprocessing def worker(): """该函数将在子进程中执行""" print('Worker') if __name__ == '__main__': # 创建子进程 p = multiprocessing.Process(target=worker) # 启动子进程 p.start() # 等待子进程结束 p.join()
在上面的代码中,worker函数将在子进程中执行。首先,创建了一个Process对象,指定target参数为worker函数。然后,通过调用start方法启动子进程,最后调用join方法等待子进程结束。
如果需要创建大量的进程,那么使用Process类可能会导致系统资源的浪费。此时,可以使用Pool类来创建进程池。下面是一个简单的示例:
import multiprocessing def worker(num): """该函数将在子进程中执行""" print('Worker %d' % num) if __name__ == '__main__': # 创建进程池 pool = multiprocessing.Pool(4) # 启动进程池中的进程 pool.map(worker, range(10)) # 关闭进程池 pool.close() # 等待进程池中的进程结束 pool.join()
在上面的代码中,Pool类的构造函数中指定了进程池的大小为4,然后通过调用map方法来启动进程池中的进程。map方法会将worker函数和range(10)序列中的每个元素一一对应,然后将它们作为参数传递给进程池中的进程。最后,调用close方法关闭进程池,并调用join方法等待所有进程结束。
在多进程编程中,不同的进程之间需要进行通信。multiprocessing模块提供了多种进程间通信的方式,例如使用队列、管道、共享内存等。
队列是一种常用的进程间通信方式。multiprocessing模块中提供了Queue类,可以用来创建队列。下面是一个简单的示例:
import multiprocessing def producer(q): """该函数将在生产者进程中执行""" for i in range(10): q.put(i) def consumer(q): """该函数将在消费者进程中执行""" while True: item = q.get() if item is None: break print(item) if __name__ == '__main__': # 创建队列 q = multiprocessing.Queue() # 创建生产者进程 p1 = multiprocessing.Process(target=producer, args=(q,)) # 创建消费者进程 p2 = multiprocessing.Process(target=consumer, args=(q,)) # 启动进程 p1.start() p2.start() # 等待进程结束 p1.join() # 发送结束信号 q.put(None) p2.join()
在上面的代码中,首先创建了一个Queue对象,然后创建了一个生产者进程和一个消费者进程。生产者进程通过调用put方法将0~9的数字放入队列中,消费者进程通过调用get方法从队列中获取数据,并将其打印出来。最后,调用put方法发送结束信号,然后等待两个进程结束。
管道是另一种常用的进程间通信方式。multiprocessing模块中提供了Pipe类,可以用来创建管道。下面是一个简单的示例:
import multiprocessing def producer(conn): """该函数将在生产者进程中执行""" for i in range(10): conn.send(i) conn.close() def consumer(conn): """该函数将在消费者进程中执行""" while True: item = conn.recv() if item is None: break print(item) if __name__ == '__main__': # 创建管道 conn1, conn2 = multiprocessing.Pipe() # 创建生产者进程 p1 = multiprocessing.Process(target=producer, args=(conn1,)) # 创建消费者进程 p2 = multiprocessing.Process(target=consumer, args=(conn2,)) # 启动进程 p1.start() p2.start() # 等待进程结束 p1.join() # 发送结束信号 conn1.send(None) p2.join()
在上面的代码中,首先创建了一个管道,然后创建了一个生产者进程和一个消费者进程。生产者进程通过调用send方法将0~9的数字发送到管道中,消费者进程通过调用recv方法从管道中获取数据,并将其打印出来。最后,调用send方法发送结束信号,然后等待两个进程结束。
共享内存是一种高效的进程间通信方式,它允许多个进程共享同一块内存区域。multiprocessing模块中提供了Value和Array类,可以用来创建共享内存。下面是一个简单的示例:
import multiprocessing def worker1(n): """该函数将在进程1中执行""" n.value += 1 print('worker1:', n.value) def worker2(n): """该函数将在进程2中执行""" n.value += 1 print('worker2:', n.value) if __name__ == '__main__': # 创建共享内存 n = multiprocessing.Value('i', 0) # 创建进程1 p1 = multiprocessing.Process(target=worker1, args=(n,)) # 创建进程2 p2 = multiprocessing.Process(target=worker2, args=(n,)) # 启动进程 p1.start() p2.start() # 等待进程结束 p1.join() p2.join()
在上面的代码中,首先创建了一个Value对象,用于存储一个整数值。然后创建了两个进程,每个进程都会将共享内存中的值加1,并将其打印出来。最后,等待两个进程结束。
除了Value类之外,multiprocessing模块还提供了Array类,用于创建共享内存数组。下面是一个简单的示例:
在上面的代码中,首先创建了一个Array对象,用于存储一个整数数组。然后创建了两个进程,每个进程都会将共享内存数组中的第一个元素加1,并将其打印出来。最后,等待两个进程结束。
在使用 multiprocessing 模块进行多进程编程时,需要注意以下几点:
每个子进程都有自己的内存空间,因此全局变量在多进程之间不能直接共享。如果需要共享数据,可以使用 multiprocessing.Value 或 multiprocessing.Array 来创建共享内存。
多个进程之间需要相互通信,可以使用 multiprocessing.Queue 或 multiprocessing.Pipe 来进行进程间通信。
如果需要同时启动多个进程,可以使用进程池来管理进程。进程池可以避免频繁地启动和关闭进程所带来的开销,提高程序的效率。
每个子进程都是一个独立的进程,当子进程出现异常时,主进程并不会收到通知。因此需要在子进程中进行异常处理,并将异常信息通过进程间通信的方式传递给主进程。
可以使用 multiprocessing.Process 来创建进程,也可以使用 multiprocessing.Pool 来创建进程池。进程池可以方便地管理多个进程,避免手动启动和关闭进程所带来的麻烦。