031_进程
操作系统的发展
详情见:操作系统的发展史
# 批处理系统 —— 串行 ,速度块
# 联机批处理 —— 读磁带的时候速度快
# 脱机批处理 —— 读磁带和cpu工作并发
# 多道程序系统 —— 并行
# 操作系统的各种管理功能
# 时空的复用 : 空间隔离开来,cpu看起来可以处理多个任务
# 分时系统 —— 更好的实现了 并行
# 让cpu的工作效率下降了
# 实时系统 —— 对一个任务实时响应
# 优点:快
# 缺点 :能处理的任务更少
# 通用操作系统
# 兼具多个操作系统的特性
# 封装了对硬件的操作过程,给应用程序提供好用的接口
# 对多个作业进行调度管理来分配硬件资源
从理论角度看,是对正在运行的程序过程的抽象;
从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。
2,特征:
# 同步 调度之后 还一定要等到结果 (一条线上)
所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列
。要么成功都成功,失败都失败,两个任务的状态可以保持一致。
所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了
。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列
。
8,阻塞与非阻塞:
阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的
同步阻塞形式
异步阻塞形式
同步非阻塞形式
异步非阻塞形式
9,创建进程
但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在。
而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式创建新的进程:
1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)
无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的。
1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。
关于创建子进程,UNIX和windows
1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。
2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于windows系统来说,从一开始父进程与子进程的地址空间就是不同的。
10,进程的结束
1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
2. 出错退出(自愿,python a.py中a.py不存在)
3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)
4. 被其他进程杀死(非自愿,如kill -9)
在python程序中的进程操作
1,查看进程的 PID 号
每一个进程都有一个自己的 PID 号,可以在任务管理器,详细信息中找到这个进程。
import os
import time
print(os.getpid()) # 获取当前运行的python程序的进程id process id
print(os.getppid()) # parent process id 获取当前进程的父id
time.sleep(100)
2, python当中创建进程来替我做事情
multiprocess 模块:multiple [ˈmʌltɪpl] adj. 数量多的;多种多样的 n. 倍数
process [prəˈses] n. 过程;进程;
仔细说来,multiprocess不是一个模块而是python中一个操作、管理进程的包。 在这个包中几乎包含了和进程有关的所有子模块。由于提供的子模块非常多,为了方便归类记忆,将这部分大致分为四个部分:创建进程部分,进程同步部分,进程池部分,进程之间数据共享。
3,其中的 process 模块介绍
process 模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建
创建的是子进程。
3.1,参数介绍:
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
强调:
1, 需要使用关键字的方式来指定参数
2.,args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
参数介绍:
1, group参数未使用,值始终为None
2, target表示调用对象,即子进程要执行的任务
3, args表示调用对象的位置参数元组,args=(1,2,'egon',)
4, kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
5, name为子进程的名称
3.2,方法介绍:
1 ,p.start():启动进程,并调用该子进程中的p.run()
2, p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
3, p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
4, p.is_alive():如果p仍然运行,返回True
5, p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
3.3,属性介绍:
1 ,p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 ,p.name:进程的名称
3 ,p.pid:进程的pid
4 ,p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
5, p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
3.4,在windows中使用process模块的注意事项
在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候 ,就不会递归运行了。
4,使用 process 模块创建子进程
4.1 ,创建第一个子进程
from multiprocessing import Process
def func():
print(123)
print('我是子进程')
if __name__ == '__main__':
p = Process(target=func ) # 创建一个进程对象
p.start() # 直到执行start才有了进程
print('执行主进程的内容了')
# windows操作系统中 创建进程的语句一定要放在if __name__ == '__main__':条件语句下面
# 因为windows操作系统在创建子进程的时候会将文件整个从新执行,放在外面就会,不断的创建子进程,成递归。
4.2,验证并不是一个进程
import os
from multiprocessing import Process
def func():
print('子进程',os.getpid())
print(123)
if __name__ == '__main__':
p = Process(target=func ) # 创建一个进程对象
print('主进程',os.getpid())
p.start()
print('主进程',os.getpid())
# 结果
主进程 4552
主进程 4552
子进程 6024
4.3,为什么不是打印 主,子,主?
在执行p.start()时,只是告诉操作系统我要创建进程,并不等待结果。两个进程是异步的。
5,这是一个同步的进程
from multiprocessing import Process
def func():
print(123)
if __name__ == '__main__':
func()
6,异步阻塞
两个进程是异步的
import os import time from multiprocessing import Process def func(): print('子进程',os.getpid()) print(123) if __name__ == '__main__': p = Process(target=func ) # 创建一个进程对象 print('主进程',os.getpid()) p.start() # 子进程执行 time.sleep(10) # 主程序发生阻塞 print('取完钱了')
# 主进程阻塞,不影响子进程的执行
7,同步阻塞
import time
def func():
print(123)
if __name__ == '__main__':
time.sleep(10) # 发生阻塞 ,等待结果
func()
print('取完钱了')
8,传参,执行顺序
import os
import time
from multiprocessing import Process
def func(money):
time.sleep(3)
print('取钱 :%d'%money)
if __name__ == '__main__':
p = Process(target=func,args=(1,) ) # 可以给子进程传参,但必须传的是一个元组
p.start() #只传一个值时后面也要跟一个逗号。
print('取完钱了')
# 异步进程,虽然子进程并没有结束(没有取完钱)但是主进程已经向后执行(打印取完钱了)
# 虽然是异步进程,两进程的执行互不干扰,但是如果子进程没有执行完,即便主进程已经执行完,主进程也不会结束。只有子进程执行完才会结束主进程。
9,解决上面的问题 join方法
import os
import time
from multiprocessing import Process
def func(money):
time.sleep(3)
print('取钱 :%d'%money)
if __name__ == '__main__':
p = Process(target=func,args=(1,) )
p.start()
p.join() # p.join 就是主进程会阻塞在join的位置,等待p进程结束
print('取完钱了')
# 但是,这样又将程序阻塞,变成类似于同步
10,开启多个子线程 和 join 的使用
import os
from multiprocessing import Process
def func():
print('%d :子进程%d干的事儿,父进程:%d'%(i,os.getpid(),os.getppid()))
if __name__ == '__main__':
p = Process(target=func)
p1 = Process(target=func)
p2 = Process(target=func)
p.start()
p1.start()
p2.start()
# p.join() # 此处加上这一句,意味着,只有p子进程结束才能执行后面的。但不管其他子进程。
print('------主进程------')
11,join 的使用
import os
import time
from multiprocessing import Process
def func(i):
time.sleep(1)
print('%d :子进程%d干的事儿,父进程:%d'%(i,os.getpid(),os.getppid()))
11.1,
if __name__ == '__main__':
# 100
for i in range(10):
p = Process(target=func,args=(i,))
p.start() # 创建的子进程,执行的顺序是无序的
p.join() # 只会管最后一个创建的子进程,其他的而不管。
# 后面的程序,会在最后一个创建的子进程结束后才执行
# join如果放在for里面,就会是创建一个子程序,并且执行完之后才在创建新的子程序。
print('------主进程------')
11.2,让最后一句话在所有子进程执行完后在打印。
if __name__ == '__main__':
# 100
p_lst = []
for i in range(10):
p = Process(target=func,args=(i,))
p.start()
p_lst.append(p)
for p in p_lst:
p.join()
print('------主进程------')
12,另一种开启进程的方式
import os
from multiprocessing import Process
class MyProcess(Process):
def run(self):
print('子进程:%d'%os.getpid())
self.walk() # --->在子进程中调用
def walk(self): # 自定义的 可以不定义
print('子进程:%d' % os.getpid())
if __name__ == '__main__':
p = MyProcess()
p.start() # ---> # start会自动调用run方法
# p.walk() # ---> 在主进程中调用
print('主进程 :',os.getpid())
# 必须创建一个类 必须继承Process类
# 必须实现一个run方法
12.1,传参形式
import os
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,arg1,arg2): # 传参
super().__init__()
self.arg1 = arg1
self.arg2 = arg2
def run(self):
print('子进程:%d,%s,%s'%(os.getpid(),self.arg1,self.arg2))
self.walk() # --->在子进程中调用
def walk(self): # 自定义的 可以不定义
print('子进程:%d' % os.getpid())
if __name__ == '__main__':
p = MyProcess(1,2)
p.start() # ---> run方法
# p.walk() # ---> 在主进程中调用
print('主进程 :',os.getpid())
13, 数据隔离
# 进程与进程之间的数据是隔离的,不共享的
from multiprocessing import Process
n = 100
def func():
global n
n = n - 1
print(n)
if __name__ == '__main__':
for i in range(10):
p = Process(target=func)
p.start()
p.join()
print('主进程 :',n)
14, 进程操作实例
import socket
from multiprocessing import Process
def talk(conn):
conn.send(b'connected')
ret = conn.recv(1024)
print(ret)
if __name__ == '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()
while True:
conn,addr = sk.accept()
p = Process(target=talk,args=(conn,))
p.start()
conn.close()
sk.close()
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
ret = sk.recv(1024)
print(ret)
msg = input('>>>')
sk.send(msg.encode('utf-8'))
sk.close()