并发编程
一, 计算机硬件组成
主板 : 固化(寄存器,是直接和CPU交互的一个硬件)
CPU(中央处理器) : 计算(逻辑计算和数字计算)和控制(控制所有硬件协调工作) ;
存储(硬盘,内存)
输入设备 : 硬盘 , 鼠标 , 话筒
输出设备 : 显示器 , 音响 , 打印机
二, 计算机发展
第一代计算机 : 电子管计算机 , 及其耗电,体积庞大, 散热量特别大
第二代计算机 : 晶体管计算机
第三代计算机 : 集成电路计算机,一个板子固化几十到上百个小硬件
第四代计算机 : 大型集成电路计算机,一个板子可以达到固化十万个硬件
早期计算机以计算为核心 ; 现在计算机以存储为核心
三, 计算机操作系统 :
操作系统是一个软件,是一个能直接操纵硬件的一个软件.
人工时代 : 穿孔卡带 (操作系统还未出现)
特点 :
每个人都能自己在一段时间内独享计算机所有资源,但资源利用率低
CPU等待手工操作,CPU利用不充分
联机批处理系统
单道批处理系统
不仅使CPU得到充分利用,同时改善I/O设备和内存的利用率,提高整个系统的资源
利用效率和系统吞吐量,最终提高了整个系统的效率.
特点 : 多道 ; 宏观上多到程序并行 ; 微观上多到程序串行
多道批处理系统
特点 : 多道 ; 成批
分时系统
目标 : 对用户响应的及时,即不至于用户等待每一个命令的处理时间过长
分时技术 : 把处理机的运行时间分成很短的时间片,按时间片把处理机分配给
各联机作业使用
特性 : 多路性 ; 交互性 ; 独立性 ; 及时性
实时系统
能够及时响应随机发生的外部事件,并在严格的时间范围内完成对该事件的处理.
特点 : 及时响应 ; 高可靠性 ;
通用操作系统
个人操作系统
网络操作系统
分布式操作系统
操作系统的目标 : 让用户用起来更加轻松,
操作系统的作用 :
封装所有硬件接口 , 让各种用户使用电脑更加轻松
是对计算机内所有资源进行合理的调度和分配
dos系统 : 单用户单任务 ; Windows : 单用户多任务(早期的windoes) ; Unix : 多用户多任务.
四 , 语言的发展史:
计算机识别的是二进制语言 (机器语言)
汇编语言(指令形式)
高级语言: 面向过程语言 ; 面向对象语言
五, 进程 :
是指正在执行的程序.
是计算机中的程序关于某数据集合上的一次运行活动,
面向进程设计的计算机中 : 是程序的基本执行实体 ;
面向线程设计的计算机结构中 : 进程是线程的容器
狭义定义 : 进程是正在运行的程序的实例
广义定义 : 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.
组成 : 代码段(程序) ; 数据段(数据) ; pcb (进程控制块)
特征 : 动态性 ; 并发性 ; 独立性 ; 异步性 ;
状态 :
就绪状态 :已经获得运行需要的所有资源(操作系统分配的) ,除了CPU
执行状态 : 已经获得所有资源包括CPU ,处于正在运行
阻塞状态 : 因为各种原因,进程放弃了CPU ,导致进程无法继续执行,此时进程处于内存中
继续等待获取CPU
挂起状态 : 因为各种原因,进程放弃了CPU ,导致进程无法继续执行,此时进程被踢出内存
进程调度 : 先来先服务 ; 短作业 ; 时间片轮转 ; 多级反馈队列
并行 : 指俩件或多件事,在同一时间点同时执行
并发 : 指俩件事或多件事,在同一时间间隔内同时执行
六, 同步异步阻塞非阻塞
进程之间是相互独立的,
同步 : 一个任务的完成需要依赖另一个任务时,只有等待被依赖任务完成后,依赖的任务才算完成,这是
一种可靠地任务序列.(要摸都成功,要摸都失败,俩个任务的状态可以保持一致).
import time def func(): time.sleep(1) #间隔一秒,检验是否执行 父进程中的print('**',i) print('这是子进程') 打印 第四部 for i in range(10):#首先执行该循环 第一步 print('*',i)#打印出循环项 第二步 r = func()#执行子程序函数func 第三步 print('**',i) #必须在子进程执行完后,才能执行 第五步
异步 : 不需要等待被依赖的任务完成,只是通知被依赖的任务完成什么工作,依赖的任务也立即执行,只
要自己完成了整个任务就算完成了.至于被依赖的任务最终是否真正完成,依赖他的任务无法确定
所以他是不可靠的任务序列.
from multiprocessing import Process import time import os def func(n): #time.sleep(1) print('这里是儿子进程,儿子的pid是 %s,儿子的父进程pid是 %s ' % (os.getpid(),os.getppid())) if __name__=='__main__': p = Process(target = func,args = (1,)) #实例化一个进程,args参数是一个元组型 p.start() #开启一个进程 time.sleep(1)#当父进程阻塞时,子进程依然执行 print('这是父亲进程,父进程pid是: %s' % os,getpid()))
阻塞与非阻塞
阻塞 : 程序因为类似于IO等待,等待事件等导致无法继续执行.
非阻塞 : 程序遇到类似于IO操作时,不再阻塞等待,如果没有及时处理IO,就报错或跳过等其他操作.
阻塞与非阻塞这俩个概念与程序(线程)等待消息通知(无所谓或者异步)时的状态有关.也就是说阻
塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的.
同步/异步与阻塞/非阻塞
1. 同步阻塞形式
效率最低. (专心排队)
2. 异步阻塞形式
(异步操作是可以被阻塞的,只不过他不是在处理消息时阻塞的,而是在等待消息通知时被阻塞.)
比如 : 在银行排队办理业务,手里拿着排队的小纸条,你不能离开银行做其他事,被阻塞在了等待
的操作上面.
3. 同步非阻塞形式
效率低
比如 : 排队办业务和打电话,一边打电话一边看排到自己没,俩个操作不能同时执行,因为是同步,
必须在这俩种不同行为之间来回切换.
4. 异步非阻塞形式
效率高
效率更高
排队打电话是自己的事,通知你是语音播报(消息触发机制)的事情,程序没有在俩种不同的操作中来
回切换.
七, 开启多进程
方法一:
from multiprocessing import Process import time import os
def func(n): time.sleep(1) print('这里是儿子进程,儿子的pid是 %s,儿子的父进程pid是 %s ' % (os.getpid(),os.getppid())) if __name__=='__main__': p = Process(target = func,args = (1,)) #实例化一个进程,args参数是一个元组型 p.start() #开启一个进程 print('这是父亲进程,父进程pid是: %s' % os,getpid()))
from multiprocessing import Process import time import os def func(n): time.sleep(0.5) print('这里是儿子进程,儿子的pid是 %s,儿子的父进程pid是 %s ' % (os.getpid(),os.getppid())) if __name__=='__main__': p = Process(target = func,args = (1,)) #实例化一个进程,args参数是一个元组型 p.start() #开启一个进程 time.sleep(0.5) print('这是父亲进程,父进程pid是: %s' % (os.getpid()))
方法二: (继承)
from multiprocessing import Process import os import time class MyProcess(Process): def __init__(self,name): # self.name = name # super(MyProcess, self).__init__(name= self.name)#执行父类__init__方法 super(MyProcess, self).__init__() self.name = name def run(self): print('这是继承方式开启的子进程,名字是 %s '% self.name) if __name__ == '__main__': p1 = MyProcess('hehe') p1.start() #是指解释器告诉操作系统,去帮我开启一个进程,操作系统不一定马上执行(就绪状态) #p1.run() #告诉操作系统,马上执行这个进程(执行)
start和join
from multiprocessing import Process import os import time def func(): time.sleep(1) print('儿子在这') if __name__ == '__main__': p = Process(target=func) p.start() # time.sleep(0.5) # print('爸爸在这') #开启一个正常的子进程,父进程会等待子进程结束后,父进程也就是程序才结束 p.join()
#让主进程等待子进程执行完.现象:主进程执行到这句话阻塞,等待子进程执行,就会变成同步,不执行join就会变成异步.
time.sleep(0.5)
print('爸爸在这')
进程的其他常用
from multiprocessing import Process import os import time def func(): #time.sleep(1) print('hehe') if __name__ == '__main__': p = Process(target=func,) p.start() p.terminate() #杀死p进程,让解释器告诉操作系统,请杀掉p进程. print('子进程是否还活着?',p.is_alive()) time.sleep(0.02) print('子进程是否还活着?',p.is_alive()) #返回一个布尔值,如果返回True,代表进程还活着,如果返回False,代表进程死了 #p.is_alive()判断p进程是否还活着
守护进程特点:
随着父进程的代码执行完毕才结束 ; 守护进程不能创建子进程 ; 守护进程必须要在start()之前设置.
多个子进程
from multiprocessing import Process import os import random import time def func(i): print('我是 %s'%i) if __name__ == '__main__': l = [] addr = ['河南','山东','北京','上海'] for i in addr: p = Process(target=func,args=(i,)) p.start() #p.join()# l.append(p) [p.join() for p in l]# time.sleep(1) print('我选%s'%(random.choice(addr)))
八, 锁机制
多个进程之间内存不共享,变量不共享,操作数据时也没有先后顺序.
from multiprocessing import Process,Value import time #多个进程之间内存不贡献,变量也不共享,所以需要借助一些手段,使之共享数据(value) def get_money(num): for i in range(10): num.value -= 1 time.sleep(0.1) print('*子进程',num.value) def put_money(num): for i in range(10): num.value += 1 time.sleep(0.1) print('子进程', num.value) if __name__ == '__main__': num = Value('i',10) p = Process(target=get_money,args=(num,)) p.start() p1 = Process(target = put_money,args=(num,)) p1.start() p.join() p1.join() print(num.value) #一般情况下多个进程之间,操作数据时并没有先后顺序,容易造成数据混乱.
加锁(规范了进程顺序,防止数据混乱)
#>>>>>>一把钥匙配一把锁
from multiprocessing import Process,Value,Lock import time def get_money(num,l): l.acquire()#拿走钥匙,进门,不允许其他人进门(其它进程不能它下的数据进行操作) for i in range(10): num.value -= 1 time.sleep(0.1) print('*子进程',num.value) l.release()#还钥匙,开门,允许其他人进屋(此时其他程序允许操作它下的数据) def put_money(num,l): l.acquire()#当其他进程操作数据未归还钥匙时,此进程一直等待获取钥匙 for i in range(10): num.value += 1 time.sleep(0.1) print('子进程', num.value) l.release() if __name__ == '__main__': num = Value('i',10) l = Lock() p = Process(target=get_money,args=(num,l)) p.start() p1 = Process(target = put_money,args=(num,l)) p1.start() p.join() p1.join() print(num.value)
模拟抢票
from multiprocessing import Process,Lock import time def check(i,l): with open('余票')as f: con = f.read() print('第%s位查到票还剩%s张票' % (i, con)) def buy(i,l): l.acquire() with open('余票')as f: con = f.read() time.sleep(0.1) if int(con) > 0 : print('第%s位买到票了'% i) con = int(con) - 1 else : print('第%s位没有买到票' % i) time .sleep(0.1)#买完票后,把余票数量重新写入数据库时间的延迟 with open('余票','w') as f: f.write(str(con)) l.release() if __name__ == '__main__' : l = Lock() for i in range(10) : p1 = Process(target=check , args=(i+1 ,l)) p1.start() for i in range(10) : p1 = Process(target=buy , args=(i+1 ,l)) p1.start()
信号量
#一把锁配多把钥匙 from multiprocessing import Semaphore l = Semaphore(3) l.acquire() print(123) l.acquire() print(456) l.acquire() print(789) l.acquire()#钥匙只有三把,当钥匙用完时,程序就会阻塞在此处等待获取归还的钥匙 print(963)
from multiprocessing import Semaphore,Process import time import random def func(i,f): f.acquire() print('第%s个人进入屋里,拿走了钥匙'% i) time.sleep(random.randint(3,5)) print('第%s个人出去,还了钥匙打开门' % i) f.release() if __name__ == '__main__': f = Semaphore(3)#初始化三把钥匙,同时允许三个人进入屋内,其余人必须等待有人出来还钥匙,再进入 for i in range(10): p = Process(target=func , args=(i,f)) p.start()
九, 事件
事件是通过is_set()的bool值,去标识e.wait()的阻塞状态,当is_set()的bool值为False时,e.wait()是
阻塞状态,当is_set()的bool值为True时,e.wait()是非阻塞状态,当使用set()时,是把is_set的bool
变为True,当使用clear()时,是把is_set的bool变为False (is_set()默认为False)
e.set() ; e.clear() ; e.wait() ; e.is_set()
from multiprocessing import Even e = Even() print(e.is_set())#False wait应该是阻塞状态 e.set()#将is_set的bool值变为True,将wait变为非阻塞 e.wait() print(e.is_set) print(123) e.clear()#把is_set()的布尔值变为False print(e.is_set()) e.wait()#此处为阻塞状态,不往下进行 print(123) #结果 False True 123 False
模拟信号灯
from multiprocessing import Event , Process import time def xinhaodeng(e): while 1 : if e.is_set():#True ,代表绿灯亮,e.wait()布尔值为T time.sleep(5)#等待5秒,等车过 print('\033[31m 红灯亮! \033[0m') e.clear()#令e.wait布尔值为False else: time.sleep(5) print('\033[32m 绿灯亮! \033[0m') e.set()#令e.wait()布尔值为T def car(i,e): e.wait() print('第%s辆车过去了' % i ) if __name__ == '__main__': e = Event() triff_light = Process(target= xinhaodeng , args=(e,)) triff_light.start() for i in range(50): if i % 3 ==0: time.sleep(1) ca = Process(target=car , args=(i+1,e ,)) ca.start()