Python进程相关(一)

本文主要介绍了Python中创建和管理进程的基本概念,包括进程的并发执行、进程间通信、僵尸进程、孤儿进程和守护进程。强调了在Spyder中使用multiprocessing模块的限制,以及如何避免僵尸进程和孤儿进程的问题。通过例子展示了进程的生命周期和交互方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跟的视频,写这个博客就是为了督促自己,不写不看的话很快就忘记了吧。我就是想打好基础,慢慢来。

子进程会完全拷贝父进程的地址空间作为自己的初始状态

  • 开进程的两种方式
    法一:常用
#multiprocess类
  #创建进程
  #进程同步部分
  #进程池部分
  #进程之间数据共享
  
   #线程与进程之间的接口是一样的
#Process类创建进程的两种方式
  
    
   #方式一、最常用
import  time
import random
from  multiprocessing import Process
 
def piao(name):
     print('%s piaoing' %name)
     time.sleep(random.randrange(1,5))
     print('%s piao end' %name)
     
if __name__=='__main__':
    p1=Process(target=piao,args=('ccc',))
    p2=Process(target=piao,args=('lll',))  #一定加逗号,args参数那里
    p3=Process(target=piao,args=('ttt',))
    p4=Process(target=piao,args=('yyy',))
    
    
    p1.start()
    p2.start()
    p3.start()
    p4.start()
    print('主线程')
结果:
ccc piaoing
主线程
lll piaoing
ttt piaoing
yyy piaoing
ttt piao end
lll piao end
yyy piao end
ccc piao end

    

法二:不常用

#打开进程的方式二

from  multiprocessing import Process
import time

class MyProcess(Process):  #继承的方式
    def __init__(self,name):
        super(MyProcess,self).__init__()    
        self.name=name
        
        
        
    def run(self):
         print('%s run' %self.name)
         time.sleep(random.randrange(1,5))
         print('%s  run end' %self.name)

    
if __name__=='__main__':
    p=MyProcess('clt')
    p.start()  #其实就是p.run
    print('主进程')
结果:
主进程
clt run
clt  run end

在spyder交互模式下为multiprocessing模块在交互模式是不支持的,在 cmd 里头输入 python xxx.py 来运行起来,你就可以看到子进程的执行了

  • 进程之间内存空间间隔
#进程之间内存是隔离的,不管是否是父子进程,只要是两个进程,他们的内存空间就是互相隔离的


from multiprocessing  import Process

n=100

def task():
    global n
    n=0
    
if __name__=='__main__':
    p=Process(target=task)
    p.start()
    p.join()   #保证子进程运行完    即 父进程等待子进程运行完
    print('主进程',n)

结果:
主进程 100
  • 进程其他属性和方法
    pid,ppid,terminate(),

import  time
import os
from  multiprocessing import Process
 
def task(n):
     print('pid:%s ppid:%s is runing' %(os.getpid(),os.getppid()))
     time.sleep(n)
     #print('%s is  end' %os.getpid())
     
if __name__=='__main__':
    p=Process(target=task,args=(15,))
    
    p.start()
    print('主线程id号',os.getpid())

结果
主线程id号 3992
pid:9708 ppid:3992 is runing

发信号终止进程

p.terminate()  #给操作系统发信号,请求其回收p进程的内存空间,操作系统什么时候处理无法预料

看进程名字

p.pid    看进程id号  
p.name
  • 进程join方法
    join是用来主进程等子进程运行完毕


import  time
import os
from  multiprocessing import Process

 
def task():
     print('pid:%s ppid:%s is runing' %(os.getpid(),os.getppid()))
     time.sleep(3)
     #print('%s is  end' %os.getpid())
     
if __name__=='__main__':
    start_time=time.time()
    for i in range(5):
        p=Process(target=task)
        p.start()   #只是给os传了个信号
        
    for i in range(5):
        p.join()
    
    
    stop_time=time.time()
    print('主进程等待了%s'%(stop_time-start_time))
    print('主线程pid:%s ' %os.getpid())

结果:
pid:13372 ppid:9852 is runing
pid:2344 ppid:9852 is runing
pid:10652 ppid:9852 is runing
pid:17096 ppid:9852 is runing
pid:396 ppid:9852 is runing
主进程等待了3.4717772006988525   #因为是并发
主线程pid:9852

以上这些进程是并发
若要串行:

import  time
import os
from  multiprocessing import Process

 
def task():
     print('pid:%s ppid:%s is runing' %(os.getpid(),os.getppid()))
     time.sleep(3)
     #print('%s is  end' %os.getpid())
     
if __name__=='__main__':
    start_time=time.time()
    for i in range(5):
        p=Process(target=task)
        p.start()   #只是给os传了个信号
        p.join()   #让父进程等待子进程
    
    
    stop_time=time.time()
    print('主进程等待约%s'%(stop_time-start_time))
    print('主线程pid:%s ' %os.getpid())

结果:
pid:1236 ppid:16328 is runing
pid:7124 ppid:16328 is runing
pid:9532 ppid:16328 is runing
pid:5148 ppid:16328 is runing
pid:12680 ppid:16328 is runing
主进程等待约16.06013584136963   因为是串行
主线程pid:16328 

  • 僵尸进程
    没有把所有的资源都让出来
    这是一种数据结构
    所有的子进程都会经历这个状态
    子进程运行完不完全释放,让他保留一些信息让主进程用
    什么时候产生:父进程没结束,子进程先结束
    害处:占用PID号
    什么时候销毁:父进程说了算,所有子进程都死了发一个 wait(pid)系统调用
    本身是一个正常的状态,是一个让父进程可以随时查看子进程的状态,即使子进程已经死了
    父进程死了,僵尸进程由init管回收,init是liux中所有进程的父进程
    解决僵尸进程的方法
    1:杀死父进程
    2:对开启的子进程记得使用join,join中会调用wait系统调用回收进程
    3: 处理 SIGCHLD 信号
  子进程退出时系统会向父进程发送 SIGCHLD 信号,父进程可以通过注册 SIGCHLD 信号处理程序,在信号处理程序中调用 wait 系统调用来清理僵尸进程。
  1. 孤儿进程
    父进程先子进程死
    孤儿进程会被init进程(pid为1)所收养并完成其状态手机工作
    孤儿进程是没有害的
  2. 守护进程
    1、开子进程的目的是让任务并发执行
    2、 守护进程伴随着整个主进程的生命周期,主进程死,则守护进程也不存在了
    3、什么时候应该把一个子进程设会守护进程
    当子进程执行的任务在父进程代码运行完毕后就没有存在的意义。此时,将其设为守护进程
开始此子进程之前
 p.deamon=True    #表示将子进程设为守护进程
 p.start()  
 #不可以在子进程开启之后才设deamon

4、效果是,主进程代码运行完毕,守护进程也就跟着主进程一起死掉
5、守护进程中不可再开子进程,即target对象中不可以定义子进程
因为容易产生孤儿进程,孤儿进程多的话也是麻烦事
6、守护进程也是子进程的一类

from multiprocessing import Process
#from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")


p1=Process(target=foo)
p2=Process(target=bar)

p1.daemon=True
p1.start()  #仅是发信号,不可能一发信号就执行
p2.start()
print('main---')
#此时有三种进程运行
由于程序开子进程没那么快,那么最后一句代码会执行,那么主进程就死了,那么守护进程P1就结束了,还没等待p1执行。p2不受影响

结果:
main---
456
end456

上边的并不是唯一结果,因为可能主机运行特别快,P2开没开始P1就运行了,模拟如下

from multiprocessing import Process
#from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")
if __name__=='__main__':

    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    time.sleep(1)  #让p1来得及运行
    p2.start()
    
    print('main---')
结果:
123
main---
456
end456

也有可能执行打印main—时,p1启动,导致屏幕上main123—这也是有可能 因为不同机器执行速度不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值