第十五章 并发编程
Posted gnaix
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十五章 并发编程相关的知识,希望对你有一定的参考价值。
1.操作系统的发展史
参考:http://www.cnblogs.com/Eva-J/articles/8253521.html
知识点
输入输出 -- 大部分时间都不会占用CPU,但会降低你程序的效率
操作系统的三种基本类型:多道批处理系统、分时系统、实时系统。
现在操作系统
基于多道批处理系统和分时系统
多个程序、作业在遇到IO操作的时候,操作系统会帮助你进行切换
让CPU的利用率得到最大的提高
2.进程
初识进程
进程: 运行中的程序
操作系统 只负责管理调度进程
进程是操作系统中资源分配的最小单位
每一个运行中的程序都需要有自己的内存、资源
都分配给进程 记录执行的状态 管理自己的内存资源
在Python中,每一个运行的程序 都是一个进程
如何使用python来开启一个进程--我们使用multiprocessing模块,process-进程,multi多元的
并发编程例:
import os import time from multiprocessing import Process def func(num): print(num,os.getpid()) time.sleep(0.5) print(num,os.getpid()) time.sleep(0.5) print(num, os.getpid()) time.sleep(0.5) print(num, os.getpid()) # 创建一个进程 if __name__ == ‘__main__‘: # windows,开启子进程的时候,会执行import print(os.getpid()) p = Process(target=func, args=(10,)) p.start() # 开启进程 print(os.getpid()) time.sleep(1) print(os.getpid(),1) time.sleep(1) print(os.getpid(),2) # 运行结果 # 时间轴 # 17500 0 # 17500 0 # 10 12656 0+ # 10 12656 0.5 # 17500 1 1 # 10 12656 1+ # 10 12656 1.5+ # 17500 2 2
几个概念:
同步:一个时刻只能做一件事
异步:同时做多件事
异步可以有效地提高程序的效率子
进程:主进程中开启的新的进程
主进程:运行的这个程序
父进程:创造出子进程的进程
注意:进程与进程之间都是异步的,而且开启一个进程是有时间开销的
进程的进阶
什么是进程:运行中的程序,计算机中最小的资源分配单位
程序开始执行就会产生一个主进程
python中可以主进程中用代码启动一个进程 -- 子进程
同时主进程也被称为父进程父子进程之间的代码执行是异步的,各自执行自己的
父子进程之间的数据不可以共享
例:
import time from multiprocessing import Process n = 100 def func(): global n n = 0 print(n) print(‘----------‘) if __name__ == ‘__main__‘: Process(target=func).start() time.sleep(1) print(n) # 0 # ---------- # 100 # 说明:父进程中n的值并没有随着子进程的运行而改变
进程什么时候结束
主进程什么时候结束:主进程会等待子进程结束之后再结束,父进程会等待回收子进程所占用的资源
例:直接开启多个子进程
import time from multiprocessing import Process n = 100 def func(n): time.sleep(1) print(‘-‘*n) if __name__ == ‘__main__‘: Process(target=func, args=(1,)).start() Process(target=func, args=(2,)).start() Process(target=func, args=(3,)).start() Process(target=func, args=(4,)).start() # 说明:主要看时间片的轮转,是一个随机事件 # - # ---- # --- # --
例:使用for循环开启多个子进程
import time from multiprocessing import Process n = 100 def func(n): time.sleep(1) print(‘-‘*n) if __name__ == ‘__main__‘: for i in range(10): Process(target=func, args=(i,)).start() # - # -- # -------- # ---- # --- # ----- # --------- # ------ # -------
阻塞
例:使用阻塞(join)开启子进程
import time from multiprocessing import Process n = 100 def func(n): time.sleep(1) print(‘-‘*n) if __name__ == ‘__main__‘: p = Process(target=func, args=(1,)) p.start() print(‘子进程开始了‘) p.join() # 阻塞 直到子进程都执行完毕 print(‘十条信息已经都发送完了‘) # 子进程开始了 # - # 十条信息已经都发送完了
例:使用阻塞(join)循环开启多个子进程
import time from multiprocessing import Process n = 100 def func(n): time.sleep(1) print(‘-‘*n) if __name__ == ‘__main__‘: lst = [] for i in range(10): p = Process(target=func, args=(i,)) p.start() lst.append(p) for p in lst:p.join() print(‘十条信息已经都发送完了‘) # ----- # - # --- # ------- # -- # --------- # ---- # -------- # ------ # # 十条信息已经都发送完了
守护进程
守护进程也是一个子进程
定义:当主进程的代码执行完毕之后自动结束的子进程叫做守护进程
例:
import time from multiprocessing import Process def deamon_func(): while True: print(‘我还活着‘) time.sleep(0.5) if __name__ == ‘__main__‘: p = Process(target=deamon_func) # 开启守护进程 p.daemon = True p.start() for i in range(3): print(i*‘*‘) time.sleep(0.4) # 我还活着 # * # 我还活着 # ** # 我还活着 # 说明:正常情况下,父进程会等待子进程结束才结束 # 而设置守护进程后,父进程结束了,子进程的死循环即可停止
练习:分析程序请问会打印多少个我还活着
import time from multiprocessing import Process def deamon_func(): while True: print(‘我还活着‘) time.sleep(0.5) def wahaha(): for i in range(10): time.sleep(1) print(i*‘#‘) if __name__ == ‘__main__‘: Process(target=wahaha).start() p = Process(target=deamon_func) p.daemon = True p.start() for i in range(3): print(i*‘*‘) time.sleep(1) # 我还活着 # 我还活着 # * # # 我还活着 # 我还活着 # ** # # # 我还活着 # 我还活着 # ## # ### # #### # ##### # ###### # ####### # ######## # ######### # 说明:因为‘我还活着‘是守护进程打印的,所以当父进程结束后,停止打印,3/0.5=6次 # 但程序不会停止,需要等待子进程wahaha结束
例:主进程添加阻塞
import time from multiprocessing import Process def deamon_func(): while True: print(‘我还活着‘) time.sleep(0.5) def wahaha(): for i in range(10): time.sleep(1) print(i*‘#‘) if __name__ == ‘__main__‘: p2 = Process(target=wahaha) p2.start() p = Process(target=deamon_func) p.daemon = True p.start() for i in range(3): print(i*‘*‘) time.sleep(1) p2.join() # 我还活着 # 我还活着 # * # # 我还活着 # 我还活着 # ** # # # 我还活着 # 我还活着 # ## # 我还活着 # 我还活着 # ### # 我还活着 # 我还活着 # #### # 我还活着 # 我还活着 # ##### # 我还活着 # 我还活着 # ###### # 我还活着 # 我还活着 # ####### # 我还活着 # 我还活着 # ######## # 我还活着 # 我还活着 # ######### # 我还活着
总结
# 开启一个子进程 start # 子进程和主进程是异步的 # 如果在主进程中要等待子进程结束之后再执行某行代码:join # 如果有多个子进程 不能在start一个进程之后就立刻join,把所有的进程放到列表中 # 等待所有的进程都start之后再逐一join # 守护进程 -- 当主进程的代码执行完毕之后自动结束的子进程叫做守护进程
锁
添加锁是为了保证程序的运行顺序,牺牲了效率但是保护数据的安全
例:未添加阻塞、锁
import os import time import random from multiprocessing import Process,Lock def work(n): print(‘%s: %s is running‘ %(n,os.getpid())) time.sleep(random.random()) print(‘%s:%s is done‘ %(n,os.getpid())) if __name__ == ‘__main__‘: for i in range(3): p=Process(target=work,args=(i, )) p.start() # 0: 23192 is running # 2: 6064 is running # 1: 22560 is running # 1:22560 is done # 0:23192 is done # 2:6064 is done # 说明:在没有使用阻塞,锁的时候,因为时间片是随机事件,所以随机子进程开始
例:使用阻塞保证子进程的独立运行
import os import time import random from multiprocessing import Process,Lock def work(n): print(‘%s: %s is running‘ %(n,os.getpid())) time.sleep(random.random()) print(‘%s:%s is done‘ %(n,os.getpid())) if __name__ == ‘__main__‘: for i in range(3): p=Process(target=work,args=(i, )) p.start() p.join() # 0: 13184 is running # 0:13184 is done # 1: 22868 is running # 1:22868 is done # 2: 22200 is running # 2:22200 is done
例:使用锁
import os import time import random from multiprocessing import Process,Lock def work(n, lock): lock.acquire() print(‘%s: %s is running‘ %(n,os.getpid())) time.sleep(random.random()) print(‘%s:%s is done‘ %(n,os.getpid())) lock.release() if __name__ == ‘__main__‘: lock = Lock() for i in range(3): p=Process(target=work,args=(i,lock)) p.start() # 0: 18864 is running # 0:18864 is done # 1: 23264 is running # 1:23264 is done # 2: 15820 is running # 2:15820 is done
信号量
信号量本质是锁+计数器
from multiprocessing import Process,Semaphore import time,random def go_ktv(sem,user): sem.acquire() print(‘%s 占到一间ktv小屋‘ %user) time.sleep(random.randint(3,5)) #模拟每个人在ktv中待的时间不同 sem.release() print(‘%s 走出ktv小屋‘ % user) if __name__ == ‘__main__‘: sem=Semaphore(4) p_l=[] for i in range(13): p=Process(target=go_ktv,args=(sem,‘user%s‘ %i,)) p.start() p_l.append(p) for i in p_l: i.join() print(‘============》‘) # 信号量的本质就是 锁+计数器 # user12 占到一间ktv小屋 # user8 占到一间ktv小屋 # user0 占到一间ktv小屋 # user7 占到一间ktv小屋 # user12 走出ktv小屋 # user4 占到一间ktv小屋 # user6 占到一间ktv小屋 # user0 走出ktv小屋 # user8 走出ktv小屋 # user3 占到一间ktv小屋 # user7 走出ktv小屋 # user11 占到一间ktv小屋 # ****** # ============》 # 说明:程序设置Semaphore(4),表示同时只能有四个子进程存在,如果有结束的,再添加新的,知道所有子进程结束
事件
事件内部内置了一个标志
wait 方法 如果这个标志是True,那么wait == pass
wait 方法 如果这个标志是False,那么wait就会陷入阻塞,一直阻塞到标志从False变成True
一个事件在创建之初 内部的标志默认是False
False -> True set()
True -> False clear()
红绿灯模型
# 红绿灯模型 from multiprocessing import Process, Event import time, random def car(e, n): while True: if not e.is_set(): # 进程刚开启,is_set()的值是Flase,模拟信号灯为红色 print(‘