进程
进程
一、基础
- 进程三态状态转换图:
graph TB
A[创建]--提交-->B[就绪]
B[就绪]--进程调度-->C[运行]
C[运行]--时间片到-->B[就绪]
C{运行}--释放资源-->D[退出]
C{运行}--事件请求-->E[阻塞]
E[阻塞]--保存现场-->F[发生阻塞的进程数据存储到栈]
F[发生阻塞的进程数据存储到栈]--恢复现场-->B[就绪]
注意:
- 栈是一种数据的存储方式,基本的特点是先进后出,具有这种特点的统称为栈。
- 计算机中栈的一般大小是几个兆,如果希望拿出先进的数据,必须把它后进的数据全部取出之后才能拿出需要的数据。
- 每个进程都有自己的堆和栈,但是具体的大小是受操作系统影响的。如果不是人为的干预,一般进程之间不会共同一个空间
- 同步与异步:
- 同步:一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成之后,该任务才可以完成,这是一种可靠的任务序列。要么都成功,要么都失败,两个任务的状态保持一致。
- 异步:不需要等待被依赖任务的完成,只是通知被依赖任务需要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务是否真正的完成,依赖它的任务无法确定,所以异步是不可靠的任务序列。
- 阻塞和非阻塞:
阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关,也就是说阻塞和非阻塞主要是程序(线程)等待消息通知时的状态角度来说的。
同步/异步与阻塞/非阻塞分类:- 同步阻塞,效率最低
- 异步阻塞
- 同步非阻塞
- 异步非阻塞,效率最高
二、多进程的开启方式及方法
(一)、直接实例化对象开启
- 导入:from multiprocessing import Process
- 创建需要开启程序进行运行的程序
- if name == 'main': 这个是必须要用到的,如果不用会报错。
- 实例化一个进程对象:p = Process(target=需要开启进程的函数名/类名,args=(函数的参数)),这个参数必须是元祖形式的。
- 开启进程:p.start()
os.getpid获取当前进程的进程号,os.getppid获取当前进程的父亲进程的进程号。
from multiprocessing import Process
import time
import os
list = [('liuyang', 20), ('lili', 21)]
def func(name, age):
print('学生%s的年龄为%d' % (name, age))
time.sleep(1)
print('这里是儿子进程,进程pid为%d,父亲进程的pid为%d' % (os.getpid(), os.getppid()))
if __name__ == '__main__':
for info in list:
p = Process(target=func, args=info)
p.start()
print('这里是父亲进程,父亲进程的pid为%d,父亲的父亲进程的pid为%d' % (os.getpid(), os.getppid()))
'''
结果是:
学生liuyang的年龄为20
这里是父亲进程,父亲进程的pid为3260,父亲的父亲进程的pid为2929
学生lili的年龄为21
这里是儿子进程,进程pid为3261,父亲进程的pid为3260
这里是儿子进程,进程pid为3262,父亲进程的pid为3260
'''
(二)、通过继承线程类来开启
- 导入:from multiprocessing import Process
- 创建继承类Myprocess()
- if name == 'main': 这个是必须要用到的,如果不用会报错。
- 实例化一个进程对象:p = Process(参数)
- 开启进程:p.start()
from multiprocessing import Process
import os
class Myprocess(Process):
def __init__(self, name, age):
super().__init__()
self.name = name
# Process类中也有name参数,如果这个写在了super()前边,父类中的name就会覆盖掉本类中的name,这点需要注意
self.age = age
def get_info(self):
print('学生%s的年龄为%d' % (self.name, self.age))
print('子进程的pid为%d, 父进程的pid为%d' % (os.getpid(), os.getppid()))
return '执行结束'
if __name__ == '__main__':
p = Myprocess('黎明', 34)
p.start()
print(p.get_info())
print('子进程的进程号为%d, 父进程的进程号为%d' % (os.getpid(), os.getppid()))
'''
结果是:
学生黎明的年龄为34
子进程的pid为3992, 父进程的pid为2929
执行结束
子进程的进程号为3992, 父进程的进程号为2929
'''
p.run()和p.start()的效果都是一样的,开启一个进程。区别在于:start()是解释器告诉操作系统给我开一个进程,在就绪状态,而run()则是解释器告诉操作系统马上给我执行这个进程。start()底层调用的是run()方法。
(三)、time.sleep()和p.join()用法
- time.sleep()是把当前进行的进程阻塞住,,是的CPU可以去执行其他的进程,阻塞多长时间可以自己设定
from multiprocessing import Process
import time
def func():
for i in range(10):
time.sleep(0.1)
# sleep()的作用是造成当前进程阻塞
print('这是子进程')
if __name__ == '__main__':
p = Process(target=func)
p.start()
for i in range(10):
time.sleep(0.1)
print('这是父进程')
'''
结果是:
这是父进程
这是子进程
这是子进程
这是父进程
这是子进程
这是父进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
'''
# 子进程和父进程交替执行
需要特别注意的是:主进程和子进程正常情况下是同时在执行的,但是具体怎么执行程序控制不料,由操作系统来处理,除非人为的添加阻塞程序。
- join()方法
join()的作用就是把主进程阻塞住,让系统先执行子进程,子进程执行完之后再执行主进程。使用的情景:同步,当主进程的执行必须依赖于子进程返回的结果的时候,才用到p.join()方法。不加join()就是异步。join()必须放在start()后边,即必须在主进程开启之后才能使用。
from multiprocessing import Process
import time
def func():
for i in range(10):
time.sleep(0.1)
# sleep()的作用是造成当前进程阻塞
print('这是子进程')
if __name__ == '__main__':
p = Process(target=func)
p.start()
p.join()
# join()的作用就是把主进程阻塞住,让系统先执行子进程
for i in range(10):
print('这是父进程')
'''结果是:
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
'''
# 系统先执行了子进程,后执行主进程
(四)、p.terminate()和p.is_alive()方法
- p.terminate()方法的作用是让python解释器告诉操作系统强制杀死子进程,只执行主进程。这个方法需要慎用,如果使用该方法把子进程杀死之后,不会进行清理,创建的子进程也就成为了死锁。
- p.alive()方法的作用是判断进程是否被杀死,如果返回为True,表示进程没有被杀死,如果返回为False,表示的是进程已经被杀死。
from multiprocessing import Process
import time
def func():
for i in range(5):
time.sleep(0.1)
# sleep()的作用是造成当前进程阻塞
print('这是子进程')
if __name__ == '__main__':
p = Process(target=func)
p.start()
p.terminate()
# python解释器告诉操作系统杀死子进程
for i in range(5):
print('这是父进程')
time.sleep(0.01)
# 这里必须用time.sleep()来造成阻塞,否则无法杀死进程
print(p.is_alive())
# 判断进程是否被杀死
'''
这是父进程
False
这是父进程
False
这是父进程
False
这是父进程
False
这是父进程
False
'''
三、属性设置
-
p.name = '名字': 可以设置进程的名字属性
-
p.daemon = True:设置为守护进程,默认为False
- 守护进程不允许创建自己的子进程
from multiprocessing import Process import time def func1(): print('这是子进程开启的子进程') def func(): for i in range(5): print(time.strftime('%H:%M:%S')) time.sleep(5) # sleep()的作用是造成当前进程阻塞 p = Process(target=func1) p.start() time.sleep(2) print('这是父进程开启的子进程') if __name__ == '__main__': p = Process(target=func) p.daemon = True p.start() for i in range(5): print('这是父进程') time.sleep(1) p.join() '''结果是: 这是父进程 08:55:54 这是父进程 这是父进程 这是父进程 这是父进程 Process Process-1: Traceback (most recent call last): File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap self.run() File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run self._target(*self._args, **self._kwargs) File "open-multiprocessing.py", line 112, in func p.start() File "/usr/lib/python3.6/multiprocessing/process.py", line 103, in start 'daemonic processes are not allowed to have children' AssertionError: daemonic processes are not allowed to have children '''
- 当设置为守护进程时,只执行主进程,不执行子进程。即守护进程随着主进程(父进程)的结束而结束。
from multiprocessing import Process import time def func1(): print('这是子进程开启的子进程') def func(): for i in range(5): print(time.strftime('%H:%M:%S')) print('这是父进程开启的子进程') if __name__ == '__main__': p = Process(target=func) p.daemon = True # 设置守护进程 p.start() for i in range(5): print('这是父进程') '''结果是: 这是父进程 这是父进程 这是父进程 这是父进程 这是父进程 '''
- 在主进程中添加p.join()方法可以让守护进程运行子进程,但是子进程依然不能创建自己的子进程。
from multiprocessing import Process import time def func1(): print('这是子进程开启的子进程') def func(): for i in range(5): print(time.strftime('%H:%M:%S')) time.sleep(5) # sleep()的作用是造成当前进程阻塞 # p = Process(target=func1) # p.start() time.sleep(2) print('这是父进程开启的子进程') if __name__ == '__main__': p = Process(target=func) p.daemon = True p.start() for i in range(5): print('这是父进程') time.sleep(1) p.join() ''' 结果是: 这是父进程 08:56:24 这是父进程 这是父进程 这是父进程 这是父进程 这是父进程开启的子进程 08:56:31 这是父进程开启的子进程 08:56:38 这是父进程开启的子进程 08:56:45 这是父进程开启的子进程 08:56:52 这是父进程开启的子进程 '''
p.daemon = Ture必须设置在p.start()之前才能生效。