Python多进程并发与多线程并发编程实例总结
作者:cskchenshengkun 发布时间:2023-06-28 02:16:15
本文实例总结了Python多进程并发与多线程并发。分享给大家供大家参考,具体如下:
这里对python支持的几种并发方式进行简单的总结。
Python支持的并发分为多线程并发与多进程并发(异步IO本文不涉及)。概念上来说,多进程并发即运行多个独立的程序,优势在于并发处理的任务都由操作系统管理,不足之处在于程序与各进程之间的通信和数据共享不方便;多线程并发则由程序员管理并发处理的任务,这种并发方式可以方便地在线程间共享数据(前提是不能互斥)。Python对多线程和多进程的支持都比一般编程语言更高级,最小化了需要我们完成的工作。
一.多进程并发
Mark Summerfield指出,对于计算密集型程序,多进程并发优于多线程并发。计算密集型程序指的程序的运行时间大部分消耗在CPU的运算处理过程,而硬盘和内存的读写消耗的时间很短;相对地,IO密集型程序指的则是程序的运行时间大部分消耗在硬盘和内存的读写上,CPU的运算时间很短。
对于多进程并发,python支持两种实现方式,一种是采用进程安全的数据结构:multiprocessing.JoinableQueue,这种数据结构自己管理“加锁”的过程,程序员无需担心“死锁”的问题;python还提供了一种更为优雅而高级的实现方式:采用进程池。下面一一介绍。
1.队列实现——使用multiprocessing.JoinableQueue
multiprocessing是python标准库中支持多进程并发的模块,我们这里采用multiprocessing中的数据结构:JoinableQueue,它本质上仍是一个FIFO的队列,它与一般队列(如queue中的Queue)的区别在于它是多进程安全的,这意味着我们不用担心它的互斥和死锁问题。JoinableQueue主要可以用来存放执行的任务和收集任务的执行结果。举例来看(以下皆省去导入包的过程):
def read(q):
while True:
try:
value = q.get()
print('Get %s from queue.' % value)
time.sleep(random.random())
finally:
q.task_done()
def main():
q = multiprocessing.JoinableQueue()
pw1 = multiprocessing.Process(target=read, args=(q,))
pw2 = multiprocessing.Process(target=read, args=(q,))
pw1.daemon = True
pw2.daemon = True
pw1.start()
pw2.start()
for c in [chr(ord('A')+i) for i in range(26)]:
q.put(c)
try:
q.join()
except KeyboardInterrupt:
print("stopped by hand")
if __name__ == '__main__':
main()
对于windows系统的多进程并发,程序文件里必须含有“入口函数”(如main函数),且结尾处必须调用入口点。例如以if __name__ == '__main__': main()
结尾。
在这个最简单的多进程并发例子里,我们用多进程实现将26个字母打印出来。首先定义一个存放任务的JoinableQueue对象,然后实例化两个Process对象(每个对象对应一个子进程),实例化Process对象需要传送target和args参数,target是实现每个任务工作中的具体函数,args是target函数的参数。
pw1.daemon = True
pw2.daemon = True
这两句话将子进程设置为守护进程——主进程结束后随之结束。
pw1.start()
pw2.start()
一旦运行到这两句话,子进程就开始独立于父进程运行了,它会在单独的进程里调用target引用的函数——在这里即read函数,它是一个死循环,将参数q中的数一一读取并打印出来。
value = q.get()
这是多进程并发的要点,q是一个JoinableQueue对象,支持get方法读取第一个元素,如果q中没有元素,进程就会阻塞,直至q中被存入新元素。
因此执行完pw1.start()
pw2.start()
这两句话后,子进程虽然开始运行了,但很快就堵塞住。
for c in [chr(ord('A')+i) for i in range(26)]:
q.put(c)
将26个字母依次放入JoinableQueue对象中,这时候两个子进程不再阻塞,开始真正地执行任务。两个子进程都用value = q.get()来读取数据,它们都在修改q对象,而我们并不用担心同步问题,这就是multiProcessing.Joinable数据结构的优势所在——它是多进程安全的,它会自动处理“加锁”的过程。
try:
q.join()
q.join()
方法会查询q中的数据是否已读完——这里指的就是任务是否执行完,如果没有,程序会阻塞住等待q中数据读完才开始继续执行(可以用Ctrl+C强制停止)。
对Windows系统,调用任务管理器应该可以看到有多个子进程在运行。
2.进程池实现——使用concurrent.futures.ProcessPoolExecutor
Python还支持一种更为优雅的多进程并发方式,直接看例子:
def read(q):
print('Get %s from queue.' % q)
time.sleep(random.random())
def main():
futures = set()
with concurrent.futures.ProcessPoolExecutor() as executor:
for q in (chr(ord('A')+i) for i in range(26)):
future = executor.submit(read, q)
futures.add(future)
try:
for future in concurrent.futures.as_completed(futures):
err = future.exception()
if err is not None:
raise err
except KeyboardInterrupt:
print("stopped by hand")
if __name__ == '__main__':
main()
这里我们采用concurrent.futures.ProcessPoolExecutor对象,可以把它想象成一个进程池,子进程往里“填”。我们通过submit方法实例一个Future对象,然后把这里Future对象都填到池——futures里,这里futures是一个set对象。只要进程池里有future,就会开始执行任务。这里的read函数更为简单——只是把一个字符打印并休眠一会而已。
try:
for future in concurrent.futures.as_completed(futures):
这是等待所有子进程都执行完毕。子进程执行过程中可能抛出异常,err = future.exception()
可以收集这些异常,便于后期处理。
可以看出用Future对象处理多进程并发更为简洁,无论是target函数的编写、子进程的启动等等,future对象还可以向使用者汇报其状态,也可以汇报执行结果或执行时的异常。
二.多线程并发
对于IO密集型程序,多线程并发可能要优于多进程并发。因为对于网络通信等IO密集型任务来说,决定程序效率的主要是网络延迟,这时候是使用进程还是线程就没有太大关系了。
1.队列实现——使用queue.Queue
程序与多进程基本一致,只是这里我们不必使用multiProcessing.JoinableQueue
对象了,一般的队列(来自queue.Queue)就可以满足要求:
def read(q):
while True:
try:
value = q.get()
print('Get %s from queue.' % value)
time.sleep(random.random())
finally:
q.task_done()
def main():
q = queue.Queue()
pw1 = threading.Thread(target=read, args=(q,))
pw2 = threading.Thread(target=read, args=(q,))
pw1.daemon = True
pw2.daemon = True
pw1.start()
pw2.start()
for c in [chr(ord('A')+i) for i in range(26)]:
q.put(c)
try:
q.join()
except KeyboardInterrupt:
print("stopped by hand")
if __name__ == '__main__':
main()
并且这里我们实例化的是Thread对象,而不是Process对象,程序的其余部分看起来与多进程并没有什么两样。
2. 线程池实现——使用concurrent.futures.ThreadPoolExecutor
直接看例子:
def read(q):
print('Get %s from queue.' % q)
time.sleep(random.random())
def main():
futures = set()
with concurrent.futures.ThreadPoolExecutor(multiprocessing.cpu_count()*4) as executor:
for q in (chr(ord('A')+i) for i in range(26)):
future = executor.submit(read, q)
futures.add(future)
try:
for future in concurrent.futures.as_completed(futures):
err = future.exception()
if err is not None:
raise err
except KeyboardInterrupt:
print("stopped by hand")
if __name__ == '__main__':
main()
用ThreadPoolExecutor与用ProcessPoolExecutor看起来没什么区别,只是改了一下签名而已。
不难看出,不管是使用队列还是使用进/线程池,从多进程转化到多线程是十分容易的——仅仅是修改了几个签名而已。当然内部机制完全不同,只是python的封装非常好,使我们可以不用关心这些细节,这正是python优雅之处。
希望本文所述对大家Python程序设计有所帮助。
来源:http://blog.csdn.net/cskchenshengkun/article/details/45770627
猜你喜欢
- asp中怎么替换最后一个逗号为空字符串?举例 aaa,bbb,ccc,eee, 这个字符串怎么让最后一个逗号变没,其他的不变啊 ?问题补充:
- 一般的网站会有很多页面,面包屑导航可以大大改善用户寻找他们的路径的方法。就可用性而言,面包屑可以减少一个网站的用户返回上一级页面的操作次数,
- 前言:创建进程池可以形象地理解为创建一个并行的流水线,只需创建一次流水线的消耗,处理接收到的任务的,不使用进程池。 ,浪费时间。中方本来没有
- 一 按时间创建文件源码# 截图方式二# coding=utf-8import osimport time# 当前年月日时分秒时间 2020-
- 本文实例为大家分享了Python实现五子棋游戏的具体代码,供大家参考,具体内容如下了解游戏的规则是我们首先需要做的事情,如果不知晓规则,那么
- 1. 排名函数与PARTITION BY --所有数据 SELECT * FROM dbo.student AS a INNER JOIN
- 这篇文章主要介绍了python处理RSTP视频流过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 1、安装执行命令pip install virtualenv为了使用virtualenv更方便,可以借助 virtualenvwrapper
- 本文介绍了django反向解析URL和URL命名空间,分享给大家,具体如下:首先明确几个概念:1.在html页面上的内容特别是向用户展示的u
- 一.基于纹理背景的图像分割该部分主要讲解基于图像纹理信息(颜色)、边界信息(反差)和背景信息的图像分割算法。在OpenCV中,GrabCut
- 在html 5增加了新元素header、footer,测试过发现IE不能解析html 5新增的元素。代码如下:<!DOCTYPE&nb
- 大家都知道一些论坛的标题有高亮显示功能,在这里我不讨论也不研究论坛普遍的实现方法,下面是我的实现方法:实现思路:把要高亮显示的标题加上特定标
- 对于python,一切事物都是对象,程序中存储的所有数据都是对象,对象基于类创建计算机能处理的远不止数值,还可以处理文本、图形、音频、视频、
- 缓存(Cache)对于创建一个高性能的网站和提升用户体验来说是非常重要的,然而对我们这种只用得起拼多多的码农而言最重要的是学会如何使用缓存。
- 在Python探索之SocketServer详解中我们介绍了Python标准库中的SocketServer模块,了解了要实现网络通信服务,就
- views,中设置请求的类型class LawDetailView(View): def get(self, request, law_id
- 前端的小伙伴们在babel等的加持下,已经可以愉快的使用es6来写代码了。然后对于服务端的nodejs就有点坑爹了,虽然原生支持了es6,但
- 本文实例讲述了python使用Image处理图片常用技巧。分享给大家供大家参考。具体分析如下:使用python来处理图片是非常方便的,下面提
- 本文实例讲述了Python上下文管理器类和上下文管理器装饰器contextmanager用法。分享给大家供大家参考,具体如下:一. 什么是上
- 前言一首歌热门了,参与评论的人也很多,这时无论好坏评论都来了,没有人控评得话,指不定乱七八糟但是自己有喜欢看评论,不想影响好心情,想看看精彩