python中多进程+协程的使用

2024-02-23 02:58

本文主要是介绍python中多进程+协程的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先强调背景:        
1、GIL是什么?
    GIL的全称是Global Interpreter Lock(全局解释器锁),为了数据安全所做的决定。 
    GIL全局解释器锁: 
    同一进程下的多线程共享数据,共享意味着竞争,竞争带来无序,为了数据安全所以需要加锁进行数据保护,GIL本质是一把 互斥锁,使并发变为串行,保证同一时间只有一条线程访问解释器级别的数据,这样就保证了解释器级别的数据安全,同时也带来了一些问题,同一进程只有一条线程执行任务,无法利用多核优势,解决方案可以根据任务的类型来处理,如果是I/O密集型,则需要开多线程提高效率,如果是计算密集型则需要多进程。
      

2、每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲
    都是同时处理多路请求的概念。但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多
    事件在同一时间间隔内发生。)


在Python多线程下,每个线程的执行方式
1、获取GIL
2、执行代码直到sleep或者是python虚拟机将其挂起。
3、释放GIL        
可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,
     GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。        

在Python2.x里,GIL的释放逻辑是当前线程遇见IO操作或者ticks计数达到100(ticks可以看作是Python自身的一个计数器,专门做用于GIL,每次释放后归零,这个计数可以通过 sys.setcheckinterval 来调整),进行释放。        

每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行),这就是为什么在多核CPU上,python的多线程效率并不高。    

什么是协程:

        是一种用户的轻量级的线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器和栈存放在制定地方,在切           换回来的时候,恢复先前的上下文和栈,

         作用:   协程能保留上次调用的状态,每次过程重入时,就相当于进入上次调用的状态(上次离开时所处的逻辑流位置)

        在并发编程中,协程和线程类似,每个协程表示一个执行单元,拥有自己的本地数据,与其他协程共同享用全局数据的其他资源。

为什么使用协程:

  1.  与协程相关的是协作多任务,不管是进程还是线程,每次阻塞、切换都要调用操作系统,先让CPU 跑操作系统的执行程序,然后再让调度程序决定先执行哪个线程或者进程
  2. 由于抢占式调度顺序的不确定的特点,使用线程要非常注意处理同步问题这块,但是协程完全不用考虑这个问题
  3. 因为协程是用户自己编写调度逻辑的,对cpu来说,协程就是单线程,cpu就不用考虑上下文调度和切换的问题,就省去了cpu调度的开销,所有协程在一定程度上要优于线程    


怎么使用协程:      简单来说,使用gevent
  1. 可以不受线程开销的限制, 把20w左右的url放到单进程的协程都没问题
  2. 最佳推荐的方式:多进程+协程(每个进程都看作是单线程,把这个单线程协程化)

隐藏的问题:

        进程的数量会随着url数量的增加而不断增加,我们在这里不使用进程池multiprocessing.Pool来控制进程数量的原因是multiprocessing.Pool和gevent有冲突不能同时使用,有兴趣的同学可以研究一下为什么会冲突。并且在已经知道url有多少条的情况下,我们完全可以通过控制每个进程处理的url数量来控制进程数

总结:

        多进程+协程:避免了cpu调度调度的开销,又把cpu充分的利用起来,对于爬取大量的数据信息和文件读写的效率都有很大的提高。



这篇关于python中多进程+协程的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/737306

相关文章

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Linux进程CPU绑定优化与实践过程

《Linux进程CPU绑定优化与实践过程》Linux支持进程绑定至特定CPU核心,通过sched_setaffinity系统调用和taskset工具实现,优化缓存效率与上下文切换,提升多核计算性能,适... 目录1. 多核处理器及并行计算概念1.1 多核处理器架构概述1.2 并行计算的含义及重要性1.3 并

Linux下进程的CPU配置与线程绑定过程

《Linux下进程的CPU配置与线程绑定过程》本文介绍Linux系统中基于进程和线程的CPU配置方法,通过taskset命令和pthread库调整亲和力,将进程/线程绑定到特定CPU核心以优化资源分配... 目录1 基于进程的CPU配置1.1 对CPU亲和力的配置1.2 绑定进程到指定CPU核上运行2 基于

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

prometheus如何使用pushgateway监控网路丢包

《prometheus如何使用pushgateway监控网路丢包》:本文主要介绍prometheus如何使用pushgateway监控网路丢包问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录监控网路丢包脚本数据图表总结监控网路丢包脚本[root@gtcq-gt-monitor-prome

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、