python学习 第九周知识回顾(并发编程)

106 阅读5分钟

并发编程

操作系统发展史

穿孔卡片>>>联机批处理系统>>>脱机批处理系统
                              (cpu利用率的发展史)

多道技术

  • 基于单核的前提
单道按序排队效率低,多道一心多用,合理安排效率高
  • 切换+保存状态
切换      cpu进入IO操作或长时间占用会切换程序执行
保存状态  切换前记录当前执行状态,切换后依此状态执行

进程

进程理论

  • 正在被运行的程序称为进程
  • 进程调度算法
先来先服务算法>>>短作业优先>>>时间片轮转法+多级反馈队列
                                         均分时间,优先降低

并行与并发

  • 多个进程同时执行称为并行(多核实现,属于并发)
  • 多个进程看起来像同时执行称为并发(多单核无所谓)

三种状态

阻塞态与非阻塞态(就绪态,运行态)

image.png

同步与异步

  • 提交任务等待,得到结果的行为称为同步
  • 提交任务后自动提醒结果的行为称为异步
同步阻塞 
同步非阻塞
异步阻塞
异步非阻塞

创建进程的方式

1.鼠标双击
2.代码创建(两种方式)
     需要的模块      from multiprocessing import Process

IPC机制(通信)

  • 生产者消费者模型
    • 生产者产生数据,消费者处理数据
    • 完整分为三部分,生产者,消息队列,消费者
      消息队列     模块  from multiprocessing import Queue
      
  • IPC机制
    • 主进程与子进程之间的通信
    • 子进程之间的通信

相关方法

join方法

  • 让主程序在子程序结束后执行
1.直接在代码中添加time.sleep  (不合理)    X
2.join方法                   (合理)      √
  • 进程间的数据默认隔离
多个进程数据之间彼此默认互相隔离,交互需要借助管道或者队列
  • 进程相关方法
    1.查看进程号
         # 使用进程的方法需要导入currrnt_process模块 
         from multiprocessing import current_process 
         import os 
         current_process().pid # 获取当前进程的PID 
         os.getpid()           # 获取当前进程的进程号 
         os.getppid            # 获取当前进程的父进程的进程号
    
    2.销毁子进程            .terminate()
    3.判断存活状态          .is_alive()       
    

守护进程

  • 伴随着守护对象的存活或存活,死亡而死亡

僵尸进程,孤儿进程

1.进程运行结束,相关的资源未完全清空,需要父进程参与回收的叫做僵尸进程
2.父进程意外死亡,子进程正常运行,子进程就称之为孤儿进程。操作系统会自动分配进程接收孤儿进程

互斥锁

  • 互斥锁将并发变为串行(效率变低,安全性变高)
  • 互斥锁只出现在多个程序操作数据的地方

线程

线程理论

  • 进程是资源单位(车间),线程是执行单位(流程线)

线程创建

  • 两种方式与进程类似

相关方法

join方法

  • 主线程等到子线程运行结束之后再运行

线程对象相关的方法

  • 同一个进程下开设的多个线程拥有相同的进程号
  • 线程名
    from threading import Thread,current_thread 
    current_thread().name # 查看线程名 
         主进程的标识:MainThread 
         子进程的标识:Thread-N (随机的编号)
    
  • 查看进程下的线程数
active_count()

守护线程

  • 进程下的所有的非守护线程结束,主进程才能真正的结束

GIL全局解释器锁

GIL解释

    1. GIL的研究是Cpython解释器的特点 不是python语言的特点
    1. GIL本质也是一把互斥锁
    1. GIL的存在使得同一个进程下的多个线程无法同时执行(关键)
    1. GIL的存在主要是因为cpython解释器中垃圾回收机制不是线程安全的
python的多线程确实无法使用多核优势 但是在IO密集型的任务下是有用的
     GIL只确保解释器层面数据不会错乱(垃圾回收机制)
          针对程序中自己的数据应该自己加锁处理
               所有的解释型编程语言都没办法做到同一个进程下多个线程同时执行

验证GIL

  • python解释器层面的一把锁
并发流程: 
    一百个进程抢一把锁,抢到之后执行进程操作,全局中的num每抢一次就自减一, 当前进程运行完毕。其他进程又进行此操作,随后重复该操作

特点

流程:
    一百个进程抢一把锁,抢到之后执行进程操作,全局中的num每抢一次先进行 IO操作,放出抢到的锁,其他进程又可以进行抢锁。每个程序睡眠结束后自减1, 没有锁,所以每次不会继承上一次的进程的num,得到的数仍为num-1之后的数。    

python多线程

1.  单个cpu的IO密集型        多线程优势大
2.  单个cpu的计算密集型      多线程优势大
3.  多个cpu的IO密集型        多线程优势大
4.  多个cpu的计算密集型      多进程优势大

死锁现象

  • 在抢锁的时候 通过一些IO操作形成了闭环,互拿对方的锁,就会有死锁现象
    Lock() # 类名加括号每执行一次就会产生一个新的对象
    

信号量

  • 信号量本质上是多把互斥锁
  • Lock产生的是一把锁,信号量产生的是多把锁
在并发编程中    信号量就是多把互斥锁 
在django中     信号量指的是达到某个条件自动触发(中间件)

event事件

  • 子进程或者子线程之间可以彼此等待彼此
    • 子A运行到某一个代码位置后发信号告诉子B开始运行

进程池与线程池

  • 考虑到硬件的承受能力,为了保证计算机硬件的安全,所以需要进程池和线程池
  • 进程池或线程池会提前创建好固定个数的进程供程序使用,后续不会再创建
  • 使用

协程

  • 协程是程序员自己定义出出来的一种方法,可以在单线程下实现并发,效率极高
  • 实质是隐瞒IO操作,核心是自己写代码完成切换+保存状态
  • 使用