并发编程,day1
操作系统发展史
'''
主要是围绕着cpu的利用率问题
'''
多道技术
'''
单核实现并发的效果
并发:看起来像同时运行的就可以叫做并发
并行:真正意义上的同时运行
空间与时间上的复用
空间上:
多个程序共用一套计算机硬件
时间上:
切换+保存状态
'''
进程
'''
程序就是一堆死代码
进程则是正在执行的代码
'''1、先来先服务调度算法2、短作业优先调度算法3、时间片轮转法,多级反馈队列
程序运行的三种状态
'''
就绪态:一切程序必须要先过就绪状态才能加入运行态
运行态:正在被cpu执行
阻塞态:程序遇到io操作了
理想:希望开发的程序一致处于就绪态与运行态
'''
同步与异步,阻塞非阻塞
同步与异步'''任务提交方式'''
同步:任务提交之后原地的等待任务的返回结果,期间不做任何事情
异步:任务提交之后不原地等待任务返回结果,直接执行下一行代码
阻塞非阻塞'''程序运行状态'''
阻塞:阻塞态
非阻塞:就绪态,运行态
开启进程的两种方式
'''
from mutiprocessing import Proces
1、实例化产生对象
2、类的继承,run方法
ps:
在windows里面开启进程代码一定要写在main代码块内
创建一个进程就是申请一个内存空间将代码丢进去
'''
第一种方式:from multiprocessingimport Processimport timedeftask(name):print('%s is running'%name)
time.sleep(3)print('%s is over'%name)if __name__=='__main__':
p= Process(target=task,args=('jason',))
p.start()print('主')from multiprocessingimport Processimport timeclassMyProcess(Process):defrun(self)->None:print('hello bf girl')
time.sleep(1)print('get out!')if __name__=='__main__':
p= MyProcess()
p.start()print('主')
join方法
'''
主进程等待子进程代码运行完毕后再往下执行代码
'''
并发编程,day2
进程对象及其他方法
'''
一台计算机上面运行很多进程,计算机会给每一个进行的进程分配一个PID号
如何查看:
windows电脑: tasklist |findstr 22
linux:ps -aux
'''from multiprocessingimport Process,current_process
current_process().pid
os.getpid()
os.getppid()
p.terminate()
p.is_alive()
僵尸进程与孤儿进程(了解)
'''
死了但是没有死透
当你开设子进程后 该进程死后不会立刻释放占用的进程号
因为我要让父进程查看到他开设的子进程的一些基本信息 占用的pid号 运行时间等
所有的进程都会步入僵尸进程
父进程不死并且在无限制的创建子进程也不结束
回收子进程占用的pid号
父进程等待子进程运行结束
或者父进程调用join方法
''''''
子进程存活,父进程意外死亡
操作系统会开设一个儿童福利院专门管理孤儿进程,回收相关资源
'''
守护进程
from multiprocessingimport Processimport timedeftesk(name):print('%s总管正在活着'%name)
time.sleep(3)print('%s总管正在死亡'%name)if __name__=='__main__':
p= process(target= task,arg=('egon',))
p.deamon=True
p.start()print('皇帝jason寿终正寝')
互斥锁
多个进程操作同一份数据的时候,会出现数据 错乱问题
解决方法:加锁处理,将并发变成串行,牺牲效率,保证数据的安全import randomfrom multiprocessingimport Process,Lockimport timeimport jsondefsearch(i):withopen('data','r',encoding='utf-8')as f:
dic= json.load(f)print('用户%s查询余额'%(i,dic.get('ticket_num')))defbuy(i):withopen('data','r',encoding='utf-8')as f:
dic= json.load(f)
time.sleep(random.randint(1,3))if dic.get('ticket_num')>0:
dic['ticket_num']-=1withopen('data','w',encoding='utf-8')as f:
json.dump(dic,f)print('用户%s买票成功'%i)else:print('用户%s买票失败'%i)defrun(i,mutex):
search(i)
mutex.acquire()
buy(i)
mutex.release()if __name__=='__main__':
mutex= Lock()for iinrange(1,11):
p= Process(target=run,args=(i,mutex))
p.start()'''
扩展 行锁 表锁
注意:
1、锁不要轻易使用,容易造成死锁现象
2、锁旨在处理数据的部分加来保证数据安全
'''
GIL全局解释器锁
队列介绍queue
队列Queue模块'''
管道:subprocess
stdin stdout stderr
队列:管道+锁
队列:先进先出
堆栈:先进后出
'''import queue
q= queue.Queue(5)
q.put(111)
q.put(111)
q.put(111)print(q.full())
q.put(111)
q.put(111)
v1= q.get()
v2= q.get()
v3= q.get()print(q.empty())
v4= q.get()
v5= q.get()
v6= q.get_nowait()'''
q.full()
q.empty()
q.get_nowait()
再多进程的情况下是不精确
'''
进程间通信IPC机制
from multiprocessingimport Queue,Process'''
研究思路
1、主进程更子进程借助队列通信
2、子进程跟子进程借助队列通信
'''defproducet(q):
q.put('我是1号技师 很高兴为您服务')defconsumer(q):print(q.get())if __name__=='__main__':
q= Queue()
p= Process(target=producet,args=(q,))
p1= Process(target=consumer,args=(q,))
p.start()
p1.start()
生产者消费者模型
'''
生产者:生产/制造东西的
消费者:消费/处理东西的
该模型除了上述两个之外还需要一个媒介
生活中的例子,做包子的将包子做好后放在蒸笼(媒介)里面,,买包子的去蒸笼里面拿
生产者(做包子的)+消息队列(蒸笼)+消费者(吃包子的)
'''from multiprocessingimport Queue,Process,JoinableQueueimport randomimport timedefproducet(name,food,q):for iinrange(3):
data='%s生产了%s%s'%(name,food,i)
time.sleep(random.randint(1,3))print(data)
q.put(data)defconsumer(name,q):whileTrue:
food= q.get()
time.sleep(random.randint(1,3))print('%s吃了%s'%(name,food))
q.task_done()if __name__=='__main__':
q= JoinableQueue()
p1= Process(target=producet,args=('大厨','包子',q))
p2= Process(target=producet,args=('马叉虫tank','泔水',q))
c1= Process(target=consumer,args=('春哥',q))
c2= Process(target=consumer, args=('马哥', q))
p1.start()
p2.start()
c1.daemon=True
c2.daemon=True
c1.start()
c2.start()
p1.join()
p2.join()
q.join()'''
JoinableQueue 每当队列存入数据,内部会有一个计时器+1
每当你调用task_done的时候 计数器-1
q.join() 当计数器为0的时候 才往后运行
'''
线程相关知识点
1、什么是线程'''
进程:资源单位
线程:执行单位
将操作系统比喻成一个大的工程
那么进程就相当于工厂里面的车间
而线程就是车间里面的流水线
每一个进程肯定自带一个线程
再次总结:
进程:资源单位,起一个进程仅仅只是在内存空间中开辟一块独立的空间
线程:执行单位,真正被cpu执行的起始是进程里面的线程,线程指的是代码的执行过程,代码中需要使用到的资源都找所再的进程索要
进程和线程都是虚拟单位,只是为了让我们方便的描述问题
'''2、为何要有线程'''
开设进程
1、申请内存空间 耗资源
2、'拷贝代码' 耗资源
开线程:
一个进程内可以开设多个线程,在用一个进程内开设多个线程时无须再次申请内存空间及拷贝代码的操作
总结:
开设线程的开销远远小于进程的开销
同一个进程下的多个线程数据是共享的
例子:
我们开发一款文本编辑器
获取用户输入功能
实时展示到屏幕功能
自动保存在硬盘的功能
正对以上三个功能,开设进程合适还是线程合适?
开三个线程处理上面的三个功能更加合理
'''
并发编程day3
开启线程的两种方式
开进程和开线程的步骤基本都是一样的,只是导入模块不一样
类的对象调用方法
类的继承重写run方法
第一种方法:from multiprocessingimport Processfrom threadingimport Threadimport timedeftask(name):print('%s is running'%name)
time.sleep(1)print('%s is over')
t= Thread(target=task(),args=('egon',))
t.start()print('主')
第二种方法:from multiprocessingimport Processfrom threadingimport Threadimport timeclassMythead(Thread):def__init__(self,name):'''针对给类里面的参数传参需定义一个init方法'''super().__init__()
self.name= namedefrun(self)->None:print('%s is running'%self.name)
time.sleep(1)print('egon')if __name__=='__main__':
t= Mythead
t.start()print('主')
TCP服务端实现并发的效果
服务端:import socketfrom threadingimport Threadfrom multiprocessingimport Processdeftalk(conn):whileTrue:try:
data= conn.recv(1024)iflen(data)==0:breakprint(data.decode('utf-8'))
conn.send(data.upper())except ConnectionResetErroras e:print(e)break
conn.close()defserver(ip, port):
server= socket.socket()
server.bind(('127.0.0.1',8081))
server.listen(5)whileTrue:
conn, addr= server.accept()
t= Thread(target=talk, args=(conn,))
t.start()if __name__=='__main__':
s= Thread(target=server, args=('127.0.0.1',8080))
s.start()
客户端:import socket
client= socket.socket()
client.connect(('127.0.0.1',8081))whileTrue:
client.send(b'hello world')
data= client.recv(1024)print(data.decode('utf-8'))
线程对象的join方法
import ntpathimport statfrom threadingimport Threadimport timedeftask(name):print('')if __name__=='__main__':
p= Thread(target=task, args=('engon',))
p.start()
p.join()print('主')
线程间数据共享
import ntpathimport statfrom threadingimport Threadimport time
money=100deftask():global money
money=666print(money)if __name__=='__main__':
t= Thread(target=task,)
t.start()
t.join()print(money)
线程对象属性及其他方法
from threadingimport Thread,active_count,current_threadimport os,timedeftask():print('hello',current_thread().name)
time.sleep(1)if __name__=='__main__':
t= Thread(target=task)
t1= Thread(target=task)
t.start()
t1.start()print('主', active_count())
守护线程
from threadingimport Threadimport timedeftask(name):print('%s is running'%name)
time.sleep(1)print('%s is over'%name)if __name__=='__main__':
t= Thread(target=task,args=('hongwei',))
t.daemon=True
t.start()print('主')'''
主线程运行结束之后不会立刻结束,会等待其他非守护线程结束才结束
应为主线程的结束意味着所在的进程的结束
'''
例子(思考打印顺序):from threadingimport Threadimport timedeffoo():print(123)
time.sleep(1)print('end123')deffunc():print(456)
time.sleep(3)print('end456')if __name__=='__main__':
t1= Thread(target=foo)
t2= Thread(target=func)
t1.daemon=True
t1.start()
t2.start()print('主')
线程互斥锁
from threadingimport Threadfrom multiprocessingimport Lockimport time
mutex= Lock()
money=100deftask():global money
mutex.acquire()
tmp= money
time.sleep(0.1)
money= tmp-1
mutex.release()if __name__=='__main__':
t_list=[]for iinrange