python,day7,并发编程

2022-08-31 11:35:25

并发编程,day1

操作系统发展史

'''
主要是围绕着cpu的利用率问题
'''

多道技术

'''
单核实现并发的效果

并发:看起来像同时运行的就可以叫做并发
并行:真正意义上的同时运行

空间与时间上的复用
	空间上:
		多个程序共用一套计算机硬件
	时间上:
		切换+保存状态


'''#切换分为两种#1、当一个程序遇到io操作,操作系统会立刻剥夺该程序的cpu执行权限(提供了cpu利用率且不影响程序执行效率)#2、当一个程序长时间占用cpu,操作系统也会立刻剥夺该程序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__':#1、创建一个对象
            p= Process(target=task,args=('jason',))#容器类型哪怕里面只有一个元素,建议要用逗号隔开#2、开启进程
            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()#判断当前进程是否存活 True或者False

僵尸进程与孤儿进程(了解)

#僵尸进程'''
死了但是没有死透
当你开设子进程后 该进程死后不会立刻释放占用的进程号
因为我要让父进程查看到他开设的子进程的一些基本信息 占用的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']-=1#写入数据库withopen('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)# 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()#没有数据直接报错# v6 = q.get(timeout=3) #没有数据会原地等三秒,再报错#队列中如果已经没有数据的话,get方法会原地阻塞'''
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()#没有数据就会卡住#判断当前是否有结束的标识# if food is None:break
        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.put(None) #肯定再所有生产者生产数据的末尾# q.put(None)
    q.join()#等待列队中所有数据被取玩,再往下执行代码'''
JoinableQueue 每当队列存入数据,内部会有一个计时器+1
每当你调用task_done的时候 计数器-1
q.join() 当计数器为0的时候 才往后运行

'''#只要q.join执行完毕,说明消费之已经处理玩数据,消费者就没有存在的必要了#可以通过守护进程来处理

线程相关知识点

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')#开启线程不需要在main下执行代码,直接书写就可以#但是我们还是习惯性的将启动命令卸载main下面

        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')#开启线程不需要在main下执行代码,直接书写就可以#但是我们还是习惯性的将启动命令卸载main下面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()# 括号不加参数默认TCP
            server.bind(('127.0.0.1',8081))
            server.listen(5)whileTrue:
                conn, addr= server.accept()
                t= Thread(target=talk, args=(conn,))# t = Process(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',os.getpid())print('hello',current_thread().name)#子线程的名字
    time.sleep(1)if __name__=='__main__':
    t= Thread(target=task)
    t1= Thread(target=task)

    t.start()
    t1.start()# print('主',os.getpid())# print('主', current_thread().name)   #主线程的名字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
  • 作者:一只地瓜a
  • 原文链接:https://blog.csdn.net/ericezuichou/article/details/121058109
    更新时间:2022-08-31 11:35:25