并发编程
Posted zahngyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程相关的知识,希望对你有一定的参考价值。
今日内容:
1.计算机发展史(理论)
2.进程(理论)
3.创建进程的俩种方式
4.进程join方法
5.进程对象及其他方法
6.进程间数据是相互隔离的
7.守护进程
8.互斥锁
一.计算机发展史
1.操作系统发展史
1.第一带计算机 真空管和穿孔卡片 没有进程 没有操作系统
2.第二代计算机 7094 1401 晶体管 批处理系统
输入输出 以及计算设备 不能互联 需要人参与 一批一批的处理 开发效率慢 并且串行执行
3.第三代计算机 集成电路 与多道技术
多终端联机 spooling 同一台机器既能进行科学计算 又能做字符处理 通用计算机
多道技术 解决串行导致的效率低下问题
多用户终端 可以同时为多个用户提供服务 每个用户以为自己独享一台计算机
4.第四代 个人电脑
大规模使用了集成电路,大多都提供了GUI界面
2.多道技术
1.空间上的复用
多个程序共用一套计算机硬件
2.时间上的复用
切换+保存状态
1.当一个程序遇到IO操作 操作系统会剥夺该程序的cpu执行权限(提高了cpu的利用率 并且也不影响程序的执行效率)
2.当一个程序长时间占用cpu 操作系统也会剥夺该程序的cpu执行权限(降低了程序的执行效率)
并发:看起来像同时运行的就可以
并行:真正意义上的同时执行
单核的计算机能不能实现并行,但是可以实现并发
一个正在被运行的程序就称之为进程,是程序具体执行过程,一种抽象概念
进程来自于操作系统
进程与程序的区别:
程序就是一堆计算机可以识别文件,程序在没有被运行就是躺在硬盘上的一堆二进制
运行程序时,要从硬盘读取数据到内存中,CPU从内存读取指令并执行 ,
一旦运行就产生了进程
一个程序可以多次执行 产生多个进程,但是进程之间相互独立
当我们右键运行了一个py文件时 ,其实启动的是python解释器,你的py文件其实是当作参数传给了解释器
同步异步:表示的是任务的提交方式
同步:任务提交之后 原地等待的任务的执行并拿到返回结果才走 期间不做任何事(程序层面的表现就是卡住了)
异步:任务提交之后 不再原地等待 而是继续执行下一行代码(结果是要的 但是是用过其他方式获取)
阻塞非阻塞:表示的程序的运行状态
阻塞:阻塞态
非阻塞:就绪态 运行态
强调:同步异步 阻塞非阻塞是两对概念 不能混为一谈
三.创建进程的俩种方式
创建进程就是在内存中重新开辟一块内存空间
将允许产生的代码丢进去
一个进程对应在内存就是一块独立的内存空间
进程与进程之间数据是隔离的 无法直接交互
但是可以通过某些技术实现间接交互
1.直接实例化Process ,将要执行任务用target传入
1 from multiprocessing import Process 2 import time 3 4 5 def test(name): 6 print(‘%s is running‘%name) 7 time.sleep(3) 8 print(‘%s is over‘%name) 9 10 """ 11 windows创建进程会将代码以模块的方式 从上往下执行一遍 12 linux会直接将代码完完整整的拷贝一份 13 14 15 windows创建进程一定要在if __name__ == ‘__main__‘:代码块内创建 否则报错 16 """ 17 if __name__ == ‘__main__‘: 18 p = Process(target=test,args=(‘egon‘,)) # 创建一个进程对象 19 p.start() # 告诉操作系统帮你创建一个进程 20 print(‘主‘)
2.继承Process类 ,覆盖run方法 将任务放入run方法中
1 from multiprocessing import Process 2 import time 3 4 5 class MyProcess(Process): 6 def __init__(self,name): 7 super().__init__() 8 self.name = name 9 10 def run(self): 11 print(‘%s is running‘ % self.name) 12 time.sleep(3) 13 print(‘%s is over‘ % self.name) 14 15 16 if __name__ == ‘__main__‘: 17 p = MyProcess(‘egon‘) 18 p.start() 19 print(‘主‘)
四.进程join方法
Process的对象具备一个join函数
1 from multiprocessing import Process 2 import time 3 4 def test(name,i): 5 print(‘%s is running‘%name) 6 time.sleep(i) 7 print(‘%s is over‘%name) 8 if __name__ == ‘__main__‘: 9 p_list = [] 10 # for i in range(3): 11 # p = Process(target=test,args=(‘进程%s‘%i,i)) 12 # p.start() 13 # p_list.append(p) 14 # for p in p_list: 15 # p.join() 16 p = Process(target=test,args=(‘egon‘,1)) 17 p1 = Process(target=test,args=(‘kevin‘,2)) 18 p2 = Process(target=test,args=(‘jason‘,3)) 19 start_time = time.time() 20 p.start() # 仅仅是告诉操作系统帮你创建一个进程 至于这个进程什么时候创 操作系统随机决定 21 p1.start() 22 p2.start() 23 p2.join() 24 p.join() 25 p1.join() 26 27 # 主进程代码等待子进程运行结束 才继续运行 28 # p.join() # 主进程代码等待子进程运行结束 29 print(‘主‘) 30 print(time.time() - start_time)
五.进程对象及其他方法
1 from multiprocessing import Process,current_process 2 import os 3 import time 4 5 6 def test(name): 7 # print(‘%s is running‘%name,current_process().pid) 8 print(‘%s is running‘%name,‘子进程%s‘%os.getpid(),‘父进程%s‘%os.getppid()) 9 time.sleep(3) 10 print(‘%s is over‘%name) 11 12 13 if __name__ == ‘__main__‘: 14 p = Process(target=test,args=(‘egon‘,)) 15 p.start() 16 p.terminate() # 杀死当前进程 其实是告诉操作系统帮你杀死一个进程 17 time.sleep(0.1) 18 print(p.is_alive()) # 判断进程是否存活 19 # print(‘主‘,current_process().pid) 20 print(‘主‘,os.getpid(),‘主主进程:%s‘%os.getppid())
六.进程间数据是相互隔离的
1 from multiprocessing import Process 2 import time 3 4 5 money = 100 6 7 def test(): 8 global money 9 money = 99999999 10 11 12 if __name__ == ‘__main__‘: 13 p = Process(target=test) 14 p.start() 15 p.join() 16 print(money)
七守护进程
什么是守护进程
进程是一个正在运行的程序
守护进程也是一个普通进程
意思是一个进程可以守护另一个进程
例如
康熙要是一个进程的话,后宫佳丽都是守护者
如果康熙挂了, 后宫佳丽们要陪葬
结论:
如果b是a的守护进程,a是被守护的进程,a要是挂了,b也就随之结束了
使用场景:
父进程交给了子进程一个任务,任务还没有完成父进程就结束了,子进程就没有继续执行的意义了
例如:qq 接收到一个视频文件,于是开启了一个子进程来下载,如果中途退出了qq,下载任务就没必须要继续运行了
案例
1 from multiprocessing import Process 2 import time 3 4 5 def test(name): 6 print(‘%s总管正常活着‘%name) 7 time.sleep(3) 8 print(‘%s总管正常死亡‘%name) 9 10 11 if __name__ == ‘__main__‘: 12 p = Process(target=test,args=(‘egon‘,)) 13 p.daemon = True # 将该进程设置为守护进程 这一句话必须放在start语句之前 否则报错 14 p.start() 15 time.sleep(0.1) 16 print(‘皇帝jason寿正终寝‘)
八.互斥锁
什么是互斥锁
互斥锁 互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)
需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行
为什么需要互斥锁:
并发将带来资源的竞争问题 当多个进程同时要操作同一个资源时,将会导致数据错乱的问题
注意1: 不要对同一把执行多出acquire 会锁死导致程序无法执行 一次acquire必须对应一次release
注意2:想要保住数据安全,必须保住所有进程使用同一把锁
抢票案例:
1 from multiprocessing import Process,Lock 2 import time 3 import json 4 5 # 查票 6 def search(i): 7 with open(‘data‘,‘r‘,encoding=‘utf-8‘) as f: 8 data = f.read() 9 t_d = json.loads(data) 10 print(‘用户%s查询余票为:%s‘%(i,t_d.get(‘ticket‘))) 11 12 # 买票 13 def buy(i): 14 with open(‘data‘,‘r‘,encoding=‘utf-8‘) as f: 15 data = f.read() 16 t_d = json.loads(data) 17 time.sleep(1) 18 if t_d.get(‘ticket‘) > 0: 19 # 票数减一 20 t_d[‘ticket‘] -= 1 21 # 更新票数 22 with open(‘data‘,‘w‘,encoding=‘utf-8‘) as f: 23 json.dump(t_d,f) 24 print(‘用户%s抢票成功‘%i) 25 else: 26 print(‘没票了‘) 27 28 29 def run(i,mutex): 30 search(i) 31 mutex.acquire() # 抢锁 只要有人抢到了锁 其他人必须等待该人释放锁 32 buy(i) 33 mutex.release() # 释放锁 34 35 36 if __name__ == ‘__main__‘: 37 mutex = Lock() # 生成了一把锁 38 for i in range(10): 39 p = Process(target=run,args=(i,mutex)) 40 p.start()
补充孤儿进程与僵尸进程(了解)
孤儿进程
指的是,父进程先结束 ,而子进程还在运行着,
孤儿进程无害,有 其存在的必要性
例如:qq开启了浏览器,qq先退出了 浏览器应该继续运行
孤儿进程会被操作系统接管
僵尸进程
值得是,子进程已经结束了,但是操作系统会保存一些进程信息,如PID,运行时间等,此时这个进程就称之为僵尸进程
僵尸进程如果太多将会占用大量的资源,造成系统无法开启新新进程
linux 中有一个wai/waitpid 用于父进程回收子进程资源
python会自动回收僵尸进程
以上是关于并发编程的主要内容,如果未能解决你的问题,请参考以下文章