跟的视频,写这个博客就是为了督促自己,不写不看的话很快就忘记了吧。我就是想打好基础,慢慢来。
子进程会完全拷贝父进程的地址空间作为自己的初始状态
- 开进程的两种方式
法一:常用
#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 系统调用来清理僵尸进程。
- 孤儿进程
父进程先子进程死
孤儿进程会被init进程(pid为1)所收养并完成其状态手机工作
孤儿进程是没有害的 - 守护进程
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—这也是有可能 因为不同机器执行速度不同