当前位置: 首页 > 网络知识

Process用法与进程详解

时间:2026-01-29 09:27:22

僵尸与孤儿进程

僵尸进程:父进程的子进程结束的时候父进程没有wait()情况下子进程会变成僵尸进程

孤儿进程(无害)
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

情况1 无害
父进等着子进程都死,回收僵尸进程。

情况2 无害
父进程死了,子进程活着,都要被init进程接管并且回收。

情况3 有害
父进程一直不死,造成了大量僵尸进程。占用了大量的pid号

pid号是有限的。
解决方案:
最直接的办法就是杀死父进程 。

Process用法

之前我们简单介绍了如何用Process实现简单的多线程

join的用法

join 的作用主要是阻塞住主进程再等待子进程结束,然后再往下执行,(了解的是:内部会待用wait())

join的写法和start类似,一般用于start之后

fr multiprocessing import Process import time def foo(): print('进程 start ') time.sleep(2.3) print('进程 end ') if __name__ == '__main__': p = Process(target=foo) p.start() # # 核心需求就是 # time.sleep(5) p.join() # 阻塞住主进程再等待子进程结束,然后再往下执行,(了解的是:内部会待用wait()) print('主')

join的多进程用法

如果不止一个进程的话,join又会被如何使用呢

fr multiprocessing import Process import time def foo(x): print('进程 start ') time.sleep(x) print('进程 end ') if __name__ == '__main__': p1 = Process(target=foo,args=(1,)) p2 = Process(target=foo,args=(2,)) p3 = Process(target=foo,args=(3,)) start = time.time() p1.start() # p2.start() # p3.start() # # 核心需求就是 # time.sleep(5) p3.join() #1s p1.join() #1s p2.join() #1s # 总时长:按照最长的时间计算多一点。 end = time.time() print(endstart) #3s多 or 6s多 ? 正解:3s多 print('主')

在这种用法中,我们使用了三个进程。我们先将三个进程都启动,随后再同时join。我们会发现最后的结果是3秒多一点。其实这三个进程是同时开始的,当第一个进程结束的时候,第二个和第三个进程已经开始一秒多了,所以最后的结果是3秒多

当然,如果我们一个一个的start然后join也是可以达成串行的结果:

fr multiprocessing import Process import time def foo(x): print(f'进程 start ') time.sleep(x) print(f'进程 end ') if __name__ == '__main__': p1 = Process(target=foo,args=(1,)) p2 = Process(target=foo,args=(2,)) p3 = Process(target=foo,args=(3,)) start = time.time() p1.start() # p1.join() # p2.start() # p2.join() # p3.start() # p3.join() # # 不如不开,直接穿行调用函数反而快 # foo(1) # foo(2) # foo(3) end = time.time() print(endstart) print('主')

只不过这样的总时长反而高于串行,而且代码冗余,没有什么意义

join的多线程用法优化

不知道各位看官有没有觉得之前的进程每个都要写一个start和join,看上去很麻烦吗?如果三个进程还可以接受,那如果更多的进程呢?我们可以依次利用循环对其进行优化

fr multiprocessing import Process import time def foo(x): print(f'进程 start ') time.sleep(x) print(f'进程 end ') if __name__ == '__main__': start = time.time() p_list = [] for i in range(1,4): p = Process(target=foo,args=(i,)) p.start() p_list.append(p) print(p_list) for p in p_list: p.join() end = time.time() print(endstart) #3s多 or 6s多 ? 正解:3s多 print('主')

这样子代码的效果 是一样的,但是看上去就更加的简单美观了

Process其他用法

pid(),getpid()和getppid()

其他比较常见的用法是pid(),getpid()和getppid(),他们可以分别用在子进程和父进程中。我们可以直接用代码来表示用法

fr multiprocessing import Process,current_process import time,os def task(): print('子进程 start') print('在子进程中查看自己的pid',current_process().pid) # 在子进程中查看自己的pid print('在子进程中查看父进程的pid',os.getppid()) # time.sleep(200) print('子进程 end') if __name__ == '__main__': p = Process(target=task) p.start() print('在主进程查看子进程的pid',p.pid) # 一定要写在 start()之后 print('主进程的pid',os.getpid()) print('主进程的父进程pid',os.getppid()) print('主')

这些用法都是站在当前进程的角度
os.getpid():获取当前进程的pid
os.getppid():获取当前进程的父进程的pid
子进程对象.pid:获取当前进程的子进程pid

name和is_alive

p.name:进程的名称

p.is_alive():如果p仍然运行,返回True,没有运行则返回False

fr multiprocessing import Process,current_process import time def foo(): print('进程 start') # print(' ',current_process().name) time.sleep(2) print('进程 end') if __name__ == '__main__': p = Process(target=foo) # p2 = Process(target=foo,name='rocky') p.start() # p2.start() print(p.is_alive()) # True time.sleep(5) print(p.is_alive()) # 代码运行完了就算死了 False print(p.name) # print(p2.name) print('主')

terminate()

p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁

fr multiprocessing import Process,current_process import time def foo(): print('进程 start') # print(' ',current_process().name) time.sleep(4294967) print('进程 end') if __name__ == '__main__': p = Process(target=foo) p.start() p.terminate() # 给操作系统发了一个请求 print(p.is_alive()) # True p.join() print(p.is_alive()) # False print('主')

如上述代码,在使用terminate之后程序并不会睡4294967(sleep所能睡的最大的值,不要问我是怎么知道的),而是会直接结束,当然foo()函数里的所有代码都不会运行,当然,如果你在terminate之前sleep一下的话,那么在执行terminate之前的foo()里的代码还是会运行的

守护进程

守护》伴随
本质也是一个子进程
主进程的代码执行完毕守护进程直接结束。但是此时主进程可能没有结束.

fr multiprocessing import Process import time def foo(): print('守护进程 start') time.sleep(5) print('守护进程 end') if __name__ == '__main__': p = Process(target=foo) p.daemon = True # 把这个子进程定义为了守护进程 p.start() time.sleep(2) print('主')

守护进程在主进程结束后也会直接结束,上述代码中 守护进程 end 并不会被执行

fr multiprocessing import Process import time def foo(): print('守护进程 start') time.sleep(3) print('守护进程 end') def task(): print('子进程 start') time.sleep(5) print('子进程 end') if __name__ == '__main__': p = Process(target=foo) p2 = Process(target=task) p.daemon = True # 把这个子进程定义为了守护进程 p.start() p2.start() time.sleep(1) print('主')

而子进程则不一样,他并不会随着主进程结束而结束,所以它会变成孤儿进程



上一篇:Qt与C++标准的兼容之旅
下一篇:硬盘检测和维护常用软件,NAS用户必备
  • 英特尔与 Vertiv 合作开发液冷 AI 处理器
  • 英特尔第五代 Xeon CPU 来了:详细信息和行业反应
  • 由于云计算放缓引发扩张担忧,甲骨文股价暴跌
  • Web开发状况报告详细介绍可组合架构的优点
  • 如何使用 PowerShell 的 Get-Date Cmdlet 创建时间戳
  • 美光在数据中心需求增长后给出了强有力的预测
  • 2027服务器市场价值将接近1960亿美元
  • 生成式人工智能的下一步是什么?
  • 分享在外部存储上安装Ubuntu的5种方法技巧
  • 全球数据中心发展的关键考虑因素
  • 英特尔与 Vertiv 合作开发液冷 AI 处理器

    英特尔第五代 Xeon CPU 来了:详细信息和行业反应

    由于云计算放缓引发扩张担忧,甲骨文股价暴跌

    Web开发状况报告详细介绍可组合架构的优点

    如何使用 PowerShell 的 Get-Date Cmdlet 创建时间戳

    美光在数据中心需求增长后给出了强有力的预测

    2027服务器市场价值将接近1960亿美元

    生成式人工智能的下一步是什么?

    分享在外部存储上安装Ubuntu的5种方法技巧

    全球数据中心发展的关键考虑因素