Python多任务-多线程-多进程-协程-进阶学习

本文深入探讨了Python中的并发执行,包括多任务的概念、多线程、多进程及其区别。多线程由于GIL的存在实际上是伪并发,而多进程能实现真正的并发,利用多核CPU。协程则通过生成器实现轻量级的并发,适合于IO密集型任务。文中还详细讲解了进程通信、进程池和线程池的使用,以及如何通过Queue进行进程间通信。最后,介绍了迭代器、生成器和协程在数据生成与多任务执行中的应用,强调了它们在内存优化和性能提升方面的作用。
摘要由CSDN通过智能技术生成

-- 多任务-多线程-多进程-协程-进阶学习 --

文中所提到的案例参考:GITHUB中项目文件夹
https://github.com/FangbaiZhang/Python_advanced_learning/tree/master/02_Python_advanced_grammar_supplement/002_%E5%A4%9A%E7%BA%BF%E7%A8%8B_%E5%A4%9A%E8%BF%9B%E7%A8%8B_%E5%8D%8F%E7%A8%8B_%E8%BF%9B%E9%98%B6%E6%B1%87%E6%80%BB

1 多任务

1.1 多任务概念

  • 多任务举例
    什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。
    打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,
    至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。

  • 电脑多核单核
    多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。
    由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?

    答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,
    任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。
    表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,
    我们感觉就像所有任务都在同时执行一样。

    真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,
    所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

  • 并发与并行概念

    并发:指的是任务数大余cpu核数,通过操作系统的各种任务调度算法,
    实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
    并行:指的是任务数小于等于cpu核数,每个cup核同时执行不同的任务,即所有的任务真的是一起执行的(物理意义上的多任务)

    • 当多进程的任务数小于CPU的核数,多个任务同时执行,可以实现物理意义上的并行
    • 但实际中,多进程任务数远远大于CPU核数,就只能通过调度轮流执行,实现多并发
  • 关于并发、并行区别与联系

    如果你的代码是IO密集型的,线程和多进程可以帮到你。多进程比线程更易用,但是消耗更多的内存。
    如果你的代码是CPU密集型的,多进程就明显是更好的选择——特别是所使用的机器是多核或多CPU的。
    对于网络应用,在你需要扩展到多台机器上执行任务,RQ是更好的选择。

    并发是指,程序在运行的过程中存在多于一个的执行上下文。这些执行上下文一般对应着不同的调用栈。
    在单处理器上,并发程序虽然有多个上下文运行环境,但某一个时刻只有一个任务在运行。

    但在多处理器上,因为有了多个执行单元,就可以同时有数个任务在跑。
    这种物理上同一时刻有多个任务同时运行的方式就是并行。
    和并发相比,并行更加强调多个任务同时在运行。
    而且并行还有一个层次问题,比如是指令间的并行还是任务间的并行。

  • 多进程和多线程区别:

    • 多进程:多个代码片段在独立同时进行,可以同时利用多个内核,真正的多并发,同一时刻占用内存为多个进程之和

    • 多线程:多个代码片段同时执行,由于存在GIL,本质上,同时只有一个线程再执行,只有一个进程占用内存
      这个不执行,下一个才执行,内部先获取锁,释放锁,并不能发挥多核性能

    • 因此,多线程是伪多并发,同一时刻占用内存还是一个进程的

    • Python使用多进程才能利用CPU的多核资源

    • 当多进程的任务数小于CPU的核数,多个任务同时执行,可以实现物理意义上的并行

    • 但实际中,多进程任务数远远大于CPU核数,就只能通过调度轮流执行,实现多并发

  • 全局解释器(GIL)

    • Python代码的执行是由python虚拟机进行控制

    • Python语言本身并没有GIL问题,是python虚拟机(Python解释器)的问题

    • 在主循环中只能有一个线程在执行,每个线程执行的时候都需要先获取GIL,

    • 以保证同一时刻只有一个线程在执行代码

    • 线程释放GIL锁的情况:

    • 在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,

    • 但在执行完毕后,必须重新获取GIL

    • 解决多线程的GIL问题:

    • 方法1:更换python解释器(默认解释器是C语言编写的),换成java写的解释器jypython

    • 方法2:用其它语言替代多线程代码,python胶水语言,可以直接调用c语言,java语言等写的代码

  • 多线程和多进程的使用

    • 计算密集型(多进程):代码没有等待时间,使用多进程,发挥多核的性能
    • IO密集型(多线程,协程):(input,output),比如网络收发,文件读写,具有等待时间,优先使用协程,再考虑多线程
    • 比如:请求网络,发出请求,假设需要等待时间1分钟,然后返回内容,
    • 这个等待时间就可以先解锁当前线程,因为还在等待返回内容,开始下个线程
    • 等待的1分钟内可以发出多个请求,返回内容回来时候,再次请求锁,不断上锁解锁
    • 网页爬取:多线程比单线程爬取性能有提升,因为遇到IOS阻塞会自动释放GIL锁

2. 线程

  • 多线程是伪多并发
    多个代码片段同时执行,由于存在GIL,本质上,同时只有一个线程再执行,
    这个不执行,下一个才执行,内部先获取锁,释放锁
    因此,多线程是伪多并发,占用内存还是一个进程的

  • 线程

    • 一个进程的独立运行片段,一个进程可以有多个线程
    • 轻量化的进程
    • 一个进程的多个线程共享数据和上下文运行环境
    • 多线程共享全局变量
    • 共享互斥问题
  • 线程常用属性

    • threading.currentThread: 返回当前的线程变量

    • threading.enumerate(): 返回一个包含正在运行所有线程的list。

    • 正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

    • threading.activeCount(): 返回正在运行的线程数量,

    • 与len(threading.enumerate())有相同的结果。

    • 除了使用方法外,线程模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值