热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python并发编程Process对象的其他属性方法join方法详解

这篇文章主要介绍了python并发编程Process对象的其他属性方法join方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

一 Process对象的join方法

在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况

情况一:

在主进程的任务与子进程的任务彼此独立的情况下,主进程的任务先执行完毕后,主进程还需要等待子进程执行完毕,然后统一回收资源。 这种是没有join方法

情况二:

如果主进程的任务在执行到某一个阶段时,需要等待子进程执行完毕后才能继续执行,

就需要有一种机制能够让主进程检测子进程是否运行完毕,在子进程执行完毕后才继续执行,否则一直在原地阻塞,这就是join方法的作用

让主进程等着,所有子进程执行完毕后,主进程才继续执行

from multiprocessing import Process
import time
import os
def task():
  print("%s is running,parent id is <%s>" % (os.getpid(), os.getppid()))
  time.sleep(3)
  print("%s is done,parent id is <%s>" % (os.getpid(), os.getppid()))
if __name__ == "__main__":
  t = Process(target=task, )
  t.start()
  t.join()
  # 主进程 等子进程执行完了
  print("主", os.getpid(), os.getppid())
'''
is running,parent id is <25956>
is done,parent id is <25956>
主 25956 2992
'''

子进程运行完,最后打印主进程,主进程结束了 所有僵尸进程都会回收

开启多个字进程 向操作系统发送信号,但操作系统要处理的任务太多了,先开启 哪个子进程是随机的,有时候可能先开启主进程先,

操作系统什么时候开,开多长时间,我们是不知道的

from multiprocessing import Process
import time
import os
def task(name):
  print('%s is running' %name)
  time.sleep(2)
  print('%s is end' %name)
if __name__ == '__main__':
  p1 = Process(target=task, args=('子进程1',))
  p2 = Process(target=task, args=('子进程2',))
  p3 = Process(target=task, args=('子进程3',))
  p4 = Process(target=task, args=('子进程4',))
  p1.start()
  p2.start()
  p3.start()
  p4.start()
  print('主',os.getpid(),os.getppid())
'''
子进程1 is running
子进程2 is running
主 9268 5236
子进程3 is running
子进程4 is running
子进程1 is end
子进程2 is end
子进程3 is end
子进程4 is end

'''

也有可能这样,先开启主进程,

主 9556 5236
子进程1 is running
子进程3 is running
子进程2 is running
子进程4 is running
子进程1 is end
子进程3 is end
子进程2 is end
子进程4 is end

p.start() 只是给操作系统发送信号

join 会变串行?

既然join是等待进程结束, 那么我像下面这样写, 进程不就又变成串行的了吗&#63;
当然不是了, 必须明确:p.join()是让谁等?
很明显p.join()是让主线程等待p 子进程的结束,卡住的是主进程而绝非 子进程p,

from multiprocessing import Process
import time
import os
def task(name):
  print('%s is running' %(name))
  time.sleep(2)
  print('%s is end' %(name))
if __name__ == '__main__':
  p1 = Process(target=task, args=('子进程1',))
  p2 = Process(target=task, args=('子进程2',))
  p3 = Process(target=task, args=('子进程3',))
  p4 = Process(target=task, args=('子进程4',))
  p1.start()
  p2.start()
  p3.start()
  p4.start()
  p1.join()
  p2.join()
  p3.join()
  p4.join()
  print('主',os.getpid(),os.getppid())

详细解析如下:

进程只要start就会在开始运行了,所以p1-p4.start()时,系统中已经有四个并发的进程了

而我们p1.join()是在等p1结束,没错p1只要不结束主线程就会一直卡在原地,这也是问题的关键

join是让主线程等,而p1-p4仍然是并发执行的,p1.join的时候,其余p2,p3,p4仍然在运行,等#p1.join结束,可能p2,p3,p4早已经结束了,这样p2.join,p3.join.p4.join直接通过检测,无需等待

所以4个join花费的总时间仍然是耗费时间最长的那个进程运行的时间

所以不会是串行执行,是并发执行

4个join花费的总时间仍然是耗费时间最长的那个进程运行的时间

所以就是5秒,就是子进程1 那个等待的时间

from multiprocessing import Process
import time
import os
def task(name,n):
  print('%s is running' %(name))
  time.sleep(n)
  print('%s is end' %(name))
if __name__ == '__main__':
  start = time.time()
  p1 = Process(target=task, args=('子进程1',5))
  p2 = Process(target=task, args=('子进程2',2))
  p3 = Process(target=task, args=('子进程3',2))
  p4 = Process(target=task, args=('子进程4',2))
  p1.start()
  p2.start()
  p3.start()
  p4.start()
  p1.join()
  p2.join()
  p3.join()
  p4.join()
  print('主',time.time() - start)
'''
子进程1 is running
子进程2 is running
子进程3 is running
子进程4 is running
子进程2 is end
子进程3 is end
子进程4 is end
子进程1 is end
主 5.413309812545776
'''

这种方式就是串行

等子进程1执行时候,子进程2就没有发送信号,要等子进程1 执行完,再子进程2发送信号 ,开启子进程2再执行,按照这样的顺序

from multiprocessing import Process
import time
import os
def task(name,n):
  print('%s is running' %(name))
  time.sleep(n)
  print('%s is end' %(name))
if __name__ == '__main__':
  start = time.time()
  p1 = Process(target=task, args=('子进程1',5))
  p2 = Process(target=task, args=('子进程2',2))
  p3 = Process(target=task, args=('子进程3',2))
  p4 = Process(target=task, args=('子进程4',2))
  p1.start()
  p1.join()
  p2.start()
  p2.join()
  p3.start()
  p3.join()  
  p4.start()
  p4.join()
  print('主',time.time() - start)
'''
子进程1 is running
子进程1 is end
子进程2 is running
子进程2 is end
子进程3 is running
子进程3 is end
子进程4 is running
子进程4 is end
主 12.212698698043823

'''

上述启动进程与 join进程 可以简写为以下

from multiprocessing import Process
import time
import os
def task(name,n):
  print('%s is running' %(name))
  time.sleep(n)
  print('%s is end' %(name))
if __name__ == '__main__':
  start = time.time()
  p1 = Process(target=task, args=('子进程1',5))
  p2 = Process(target=task, args=('子进程2',2))
  p3 = Process(target=task, args=('子进程3',2))
  p4 = Process(target=task, args=('子进程4',2))
  process_list = [p1,p2,p3,p4]
  for p in process_list:
    p.start()
  for p in process_list:
    p.join()
  print('主',time.time() - start)

join 保证所有子进程执行完 主进程才能工作,不然一直阻塞

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • MATLAB函数重名问题解决方法及数据导入导出操作详解
    本文介绍了解决MATLAB函数重名的方法,并详细讲解了数据导入和导出的操作。包括使用菜单导入数据、在工作区直接新建变量、粘贴数据到.m文件或.txt文件并用load命令调用、使用save命令导出数据等方法。同时还介绍了使用dlmread函数调用数据的方法。通过本文的内容,读者可以更好地处理MATLAB中的函数重名问题,并掌握数据导入导出的各种操作。 ... [详细]
author-avatar
手机用户2502886253
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有