操作系统的背景知识:
操作系统的作用:
1.封装了丑陋复杂的接口,提供了良好的抽象接口
2.管理.调度程序,并将多个进程或者程序对硬件资源的竞态请求变的有序化
多道技术:
产生背景:针对于单核,实现并发
空间上的复用:内存中存在多道程序
时间上的复用:
1.遇到io口就切换
2.一个进程长时间被CPU处理的时,操作系统会强硬的将cpu调出去处理下一个进程
进程:是计算机中关于数据集合上的一次运行活动,是系统资源分配和调度的基本单位
是操作系统结构的基础
也是正在运行程序的实例
进程的调度: 先来先服务调度算法,
短作业优先调度算法,
时间片轮转法,
多级反馈队列
进程的并行并发:
并行:指的是两个或者多个cpu同时分别执行两个或者多个进程
并发:指的一个cpu对多个进程轮流交替使用
区别:虽然给人的感觉是同时执行的,但是并发是在多个进程之间交替执行
进程的同步异步:
同步:一个任务的完成需要依赖另一个任务的完成
异步:任务的完成不需要被等待的任务完成
进程的三态状态:就绪,阻塞,运行
进程的创建和结束:
创建:UNIX中调用的是fork
Windows是CreateProcess
创建子进程:UNIX和Windows
相同点:都会将父进程复制一份,存放到另一个地址空间,也就是子进程,但是两个进程之间在地址空间的操作没有关系
不同点:NUIX中子进程的地址空间是父进程的一个副本,存在只读的共享内存区的
windows的子进程空间跟父进程的进程空间多一些东西
在python程序中的进程操作:
multiprocess模块:是python中的一个操作,管理进程的包.包中几乎包含了跟进程有关的所有子模块
大致分为四类:
创建进程部分
进程同步部分
进程池部分
进程之间数据共享
1.创建进程部分(multiprocess.process模块)
process模块是一个创建进程的模块,借助这个模块就可以完成进程的创建
创建进程的时候windows必须要用if __name__=__main__():
在进程中,main之上的代码都是子进程的代码,主进程只有在子进程结束后才算真正意义上结束
import time from multiprocessing import Process #导入Process模块 def func(name): time.sleep(0.1) print('hello',name) print('我是子进程') if __name__ == '__main__': p = Process(target=func,args=('智障',)) #由Process实例化出的一个对象,表示一个子进程中的任务(尚未启动) p.start()#启动进程 time.sleep(1) print('我是主进程')
通过类的方式创建一个进程:
from multiprocessing import Process class MyProcess(Process): def __init__(self,name): super().__init__() self.name = name def run(self): print('%s正在吃饭'%self.name) if __name__ == '__main__': p = MyProcess('alex') p.start() p.join()
p.jion()的用法:是主进程等待p进程(子进程)的结束后再结束
import time from multiprocessing import Process def func(): print('子进程开始') time.sleep(1) print('子进程结束') if __name__ == '__main__': p = Process(target=func) p.start() p.join() print('主进程') # 结果: 子进程开始 子进程结束 主进程
多个进程运行时,join的用法: 多个进程执行的时候,join的个数和进程个数一样且必须连续放置
from multiprocessing import Process def func(name): print('hello',name) if __name__ == '__main__': p_l = [] for i in range(5): p = Process(target=func,args=('智障',)) p.start() p_l.append(p) for p in p_l: p.join() print('主程序')
查看进程属性:
查看进程的id:需要调用带os模块 (os.getpid , os.getppid) import os from multiprocessing import Process def func(): print('子进程',os.getpid()) # print('主进程',os.getppid()) if __name__ == '__main__': print('主进程', os.getpid()) for i in range(5): p = Process(target=func) p.start() 在子程序中os.getpid()可以查看子进程id 在主程序中os.getpid()可以查看本进程id
验证进程之间的数据隔离:
进程之间的数据是隔离的,
from multiprocessing import Process n = 100 def func(): global n n = 2 if __name__ == '__main__': p = Process(target=func) p.start() print(n)
守护进程:会随着主程序的结束而结束
1.守护进程会在主进程代码运行结束后就终止
2.守护进程内无法再开启子程序,否则抛出异常
# 主进程必须在子进程结束后回收子进程的代码后才算真正的结束
# 必须在p.start()前设置守护进程
# 守护进程若是主进程结束后,就不会再执行
import time from multiprocessing import Process 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() p2.start() time.sleep(2) print('主进程') # 结果: 123 456 end123 主进程 end456
进程的其他用法:
p.teminate()关闭进程,但是不会立即关闭 ,所以is_live立刻查看的结果还可能是True
2.进程同步(multiprocess.Lock):为了维护数据的安全,牺牲了效率利用互斥锁
from multiprocessing import Process,Lock import time import os def func(name,lock): lock.acquire() print('%s: %s 正在跑'%(name,os.getpid())) time.sleep(1) print('%s: %s已经跑完了'%(name,os.getpid())) lock.release() if __name__ == '__main__': lock = Lock() p1 = Process(target=func,args=('小明',lock)) p2 = Process(target=func,args=('小红',lock)) p1.start() p2.start()
加锁可以保证多个进程修改同一个数据的时候,只能在同一时间一个程序进行修改,就是串行修改
加锁的方式使代码的效率变低,还要自己进行加锁处理,所以大部分都是采用管道和队列的方式
(基于消息的ipc机制,进程之间的通信)
3.进程间的通信 队列 multiprocess.Queue:
import time from multiprocessing import Process,Queue def func(q): q.put([time.asctime(),'form alex','hello']) if __name__ == '__main__': q = Queue()#参数为显示队列的里的元素个数 p =Process(target=func,args=(q,)) p.start() print(q.get()) p.join()
JionableQueue()跟Queue的方法一样,但是多了几个
q.task_done()#使用此方法发出信号,表示q.get()返回的项目已经被处理;
如果调用的此方法次数大于从队列中删除的项目数量,将引发ValueError异常
q.join()生产者将使用此方法进行阻塞
# 生产者和消费者模型(欠着)
3.进程之间的数据共享(Manager模块)
Manager提供可共享的数据类型但是不加锁操作的共享数据肯定会出错
from multiprocessing import Manager,Process,Lock def work(dic,lock): with lock:#必须加锁才能保证数据的安全 dic['count'] -=1 if __name__ == '__main__': lock = Lock() m = Manager() dic = m.dict({'count':100})#设置可共享数据 p_L= [] for i in range(100): p = Process(target=work,args=(dic,lock)) p_L.append(p) p.start() for p in p_L: p.join() print(dic)
4.进程池(Pool):方便了系统调用,节省了时间,实现并发效果
from multiprocessing import Process,Pool import time def func(i): i * i return 'i'*i if __name__ == '__main__': start = time.time() p = Pool(4)#设置要开启进程数 默认为cpu的个数 for i in range(50): p.apply_async(func,(i,))#异步提交 apply提交 async异步 p.close()#关闭进程池 不允许再继续向这个池子添加任务了 p.join()#阻塞,直到已经被提交的进程池中的任务全部结束 print(time.time()-start)
返回值的获得
from multiprocessing import Pool def func(i): i * i return 'i'*i if __name__ == '__main__': p = Pool() ret_l = [] for i in range(20): ret = p.apply_async(func,(i,)) ret_l.append(ret) print(ret.get()) # for ret in ret_l: print(ret.get())#获取返回值的时候必须是ret.get() 将返回值加入列表中循环打印
同步调用:
import os import time import random from multiprocessing import Pool def func(i): time.sleep(random.random()) print(i,os.getpid()) if __name__ == '__main__': p = Pool() for i in range(20): ret = p.apply(func,(i,))
同步调用的时候 第一个进程执行完结束后才能执行,遇到io阻塞后,后面的程序都会被阻塞
Pool使用map的方法:
import time from multiprocessing import Pool def func(i): return 'i' * i if __name__ == '__main__': p = Pool() ret_l = p.map(func,range(20))#第二个为可迭代的对象 得到结果是一个列表 #map就是简单的appli_async的方式,并内置了close和join的功能 for ret in ret_l: print(ret)
回调函数callback