当前位置:   article > 正文

Python编程之多进程multiprocessing详解

multiprocessing

       Python中的multiprocessing模块提供了一种创建和管理进程的方式,使得可以利用多个CPU来加速程序运行。在这里,我会详细介绍Python中的多进程编程,包括以下内容:

  一.多进程概念

  二.multiprocessing模块介绍

  三.进程池

  四.进程通信

  五.multiprocessing的一些注意事项

  一.多进程概念

  多进程是指在同一时间内,同时执行多个程序或多个部分的程序。每个进程都拥有自己的地址空间、内存、文件描述符和其他系统资源。多进程的好处在于可以使程序并行执行,从而提高程序的运行效率。

  二.multiprocessing模块介绍

  multiprocessing模块提供了一个Process类,可以用来创建和管理进程。下面是一个简单的示例:

  1. import multiprocessing
  2. def worker():
  3. """该函数将在子进程中执行"""
  4. print('Worker')
  5. if __name__ == '__main__':
  6. # 创建子进程
  7. p = multiprocessing.Process(target=worker)
  8. # 启动子进程
  9. p.start()
  10. # 等待子进程结束
  11. p.join()
'
运行

  在上面的代码中,worker函数将在子进程中执行。首先,创建了一个Process对象,指定target参数为worker函数。然后,通过调用start方法启动子进程,最后调用join方法等待子进程结束。

  三. 进程池

  如果需要创建大量的进程,那么使用Process类可能会导致系统资源的浪费。此时,可以使用Pool类来创建进程池。下面是一个简单的示例:

  1. import multiprocessing
  2. def worker(num):
  3. """该函数将在子进程中执行"""
  4. print('Worker %d' % num)
  5. if __name__ == '__main__':
  6. # 创建进程池
  7. pool = multiprocessing.Pool(4)
  8. # 启动进程池中的进程
  9. pool.map(worker, range(10))
  10. # 关闭进程池
  11. pool.close()
  12. # 等待进程池中的进程结束
  13. pool.join()
'
运行

  在上面的代码中,Pool类的构造函数中指定了进程池的大小为4,然后通过调用map方法来启动进程池中的进程。map方法会将worker函数和range(10)序列中的每个元素一一对应,然后将它们作为参数传递给进程池中的进程。最后,调用close方法关闭进程池,并调用join方法等待所有进程结束。

  四. 进程通信

  在多进程编程中,不同的进程之间需要进行通信。multiprocessing模块提供了多种进程间通信的方式,例如使用队列、管道、共享内存等。

  (1)队列

  队列是一种常用的进程间通信方式。multiprocessing模块中提供了Queue类,可以用来创建队列。下面是一个简单的示例:

  1. import multiprocessing
  2. def producer(q):
  3. """该函数将在生产者进程中执行"""
  4. for i in range(10):
  5. q.put(i)
  6. def consumer(q):
  7. """该函数将在消费者进程中执行"""
  8. while True:
  9. item = q.get()
  10. if item is None:
  11. break
  12. print(item)
  13. if __name__ == '__main__':
  14. # 创建队列
  15. q = multiprocessing.Queue()
  16. # 创建生产者进程
  17. p1 = multiprocessing.Process(target=producer, args=(q,))
  18. # 创建消费者进程
  19. p2 = multiprocessing.Process(target=consumer, args=(q,))
  20. # 启动进程
  21. p1.start()
  22. p2.start()
  23. # 等待进程结束
  24. p1.join()
  25. # 发送结束信号
  26. q.put(None)
  27. p2.join()
'
运行

  在上面的代码中,首先创建了一个Queue对象,然后创建了一个生产者进程和一个消费者进程。生产者进程通过调用put方法将0~9的数字放入队列中,消费者进程通过调用get方法从队列中获取数据,并将其打印出来。最后,调用put方法发送结束信号,然后等待两个进程结束。

  (2)管道

  管道是另一种常用的进程间通信方式。multiprocessing模块中提供了Pipe类,可以用来创建管道。下面是一个简单的示例:

  1. import multiprocessing
  2. def producer(conn):
  3. """该函数将在生产者进程中执行"""
  4. for i in range(10):
  5. conn.send(i)
  6. conn.close()
  7. def consumer(conn):
  8. """该函数将在消费者进程中执行"""
  9. while True:
  10. item = conn.recv()
  11. if item is None:
  12. break
  13. print(item)
  14. if __name__ == '__main__':
  15. # 创建管道
  16. conn1, conn2 = multiprocessing.Pipe()
  17. # 创建生产者进程
  18. p1 = multiprocessing.Process(target=producer, args=(conn1,))
  19. # 创建消费者进程
  20. p2 = multiprocessing.Process(target=consumer, args=(conn2,))
  21. # 启动进程
  22. p1.start()
  23. p2.start()
  24. # 等待进程结束
  25. p1.join()
  26. # 发送结束信号
  27. conn1.send(None)
  28. p2.join()
'
运行

  在上面的代码中,首先创建了一个管道,然后创建了一个生产者进程和一个消费者进程。生产者进程通过调用send方法将0~9的数字发送到管道中,消费者进程通过调用recv方法从管道中获取数据,并将其打印出来。最后,调用send方法发送结束信号,然后等待两个进程结束。

  (3)共享内存

  共享内存是一种高效的进程间通信方式,它允许多个进程共享同一块内存区域。multiprocessing模块中提供了Value和Array类,可以用来创建共享内存。下面是一个简单的示例:

  1. import multiprocessing
  2. def worker1(n):
  3. """该函数将在进程1中执行"""
  4. n.value += 1
  5. print('worker1:', n.value)
  6. def worker2(n):
  7. """该函数将在进程2中执行"""
  8. n.value += 1
  9. print('worker2:', n.value)
  10. if __name__ == '__main__':
  11. # 创建共享内存
  12. n = multiprocessing.Value('i', 0)
  13. # 创建进程1
  14. p1 = multiprocessing.Process(target=worker1, args=(n,))
  15. # 创建进程2
  16. p2 = multiprocessing.Process(target=worker2, args=(n,))
  17. # 启动进程
  18. p1.start()
  19. p2.start()
  20. # 等待进程结束
  21. p1.join()
  22. p2.join()

  在上面的代码中,首先创建了一个Value对象,用于存储一个整数值。然后创建了两个进程,每个进程都会将共享内存中的值加1,并将其打印出来。最后,等待两个进程结束。

  除了Value类之外,multiprocessing模块还提供了Array类,用于创建共享内存数组。下面是一个简单的示例:

  在上面的代码中,首先创建了一个Array对象,用于存储一个整数数组。然后创建了两个进程,每个进程都会将共享内存数组中的第一个元素加1,并将其打印出来。最后,等待两个进程结束。

  五.multiprocessing的一些注意事项

  在使用 multiprocessing 模块进行多进程编程时,需要注意以下几点:

  1.全局变量的共享问题

  每个子进程都有自己的内存空间,因此全局变量在多进程之间不能直接共享。如果需要共享数据,可以使用 multiprocessing.Value 或 multiprocessing.Array 来创建共享内存。

  2.进程间通信问题

  多个进程之间需要相互通信,可以使用 multiprocessing.Queue 或 multiprocessing.Pipe 来进行进程间通信。

  3.进程池的使用

  如果需要同时启动多个进程,可以使用进程池来管理进程。进程池可以避免频繁地启动和关闭进程所带来的开销,提高程序的效率。

  4.子进程的异常处理

  每个子进程都是一个独立的进程,当子进程出现异常时,主进程并不会收到通知。因此需要在子进程中进行异常处理,并将异常信息通过进程间通信的方式传递给主进程。

  5.进程的启动方式

  可以使用 multiprocessing.Process 来创建进程,也可以使用 multiprocessing.Pool 来创建进程池。进程池可以方便地管理多个进程,避免手动启动和关闭进程所带来的麻烦。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/860668
推荐阅读
相关标签
  

闽ICP备14008679号