当前位置: 首页 > 科技观察

提升CPU算力,在Python中使用多进程模型

时间:2023-03-20 22:39:22 科技观察

提高CPU计算能力和使用Python中的多进程模型的瓶颈,摩尔定律已经过期。性能提升更侧重于使用多核并发,而不是依赖单核性能。俗话说,个人再强,也敌不过训练有素的团队。这是事实。但即便是使用多核,也分为多进程、多线程等不同的解决方案。我们经常听到老手说:“python下多线程没什么用,推荐多进程!”你为什么这么说?要知道为什么,还要知道为什么。于是有了下面的深入研究。Part01概述目前,在算力网络的发展过程中,经常会有并行计算的需求。在python中,如果使用多线程进行并行,就会面临一个尴尬的问题:一个核工作,其他核看。为什么会有这么尴尬的问题?是因为python中GIL锁的存在。什么是GIL?GIL的全称是全局解释器锁(GlobalInterpreterLock)。源码是python设计之初的考虑。为了数据安全,每个进程都有一个单独的GIL锁。流程是什么?进程是程序的一个执行过程,是一个动态的概念,是程序执行过程中分配和管理资源的基本单位。什么是线程?线程是CPU调度和分派的基本单位,它可以与属于同一进程的其他线程共享一个进程拥有的所有资源。进程和线程的关系?线程是进程的一部分,一个线程只能属于一个进程,一个进程可以有多个线程,但至少有一个线程。为什么要使用多进程和多线程?现代CPU通常是多核CPU。如果业务代码是单进程/单线程的,那么在运行时实际上只能使用一个CPU核心,其他核心只能被浪费。为了提高代码运行效率,我们采用多进程或者多线程,充分利用多个CPU核心来提高代码执行效率。Part02执行原理每个CPU核心只能同时执行一个线程(单核CPU下的多线程其实只是并发,不是并行。从宏观上看,并发和并行都是同时处理多个请求的概念但并发和并行是有区别的,并行是指两个或多个事件同时发生;而并发是指两个或多个事件在同一时间间隔内发生。)Python多线程下,每个线程的Execution方法:让GIL执行代码直到sleep或者python虚拟机挂起。GIL的发布表明,线程要想执行,必须先获取GIL。我们可以把GIL看作是一张“通行证”,一个python进程中只有一个GIL。得不到pass的线程是不允许进入CPU执行的。在python2.x中,GIL的释放逻辑是当前线程遇到IO操作或者ticks计数达到100(ticks可以看作是python本身的一个计数器,专门用于GIL,归零每次释放后。这个计数可以通过sys.setcheckinterval来调整),释放。并且每次释放GIL锁时,线程都会竞争锁并切换线程,消耗资源。而且因为有GIL锁,python中一个进程只能同时执行一个线程(拿到GIL的线程才能执行),这也是为什么python的多线程在多核CPU上效率不高的原因。Part03实际场景分析在实际应用场景中,并不是所有的业务都能把CPU跑满,也不是所有的业务都需要使用多进程。接下来分类别讨论:1.CPU密集型业务(各种Loop处理、计数、数学计算等),这种情况下ticks计数很快就会达到阈值,然后触发释放,重新竞争GIL的(多个线程来回切换,当然会消耗资源),所以python多线程对CPU密集型代码并不友好。2、对于IO密集型业务(文件处理、网络爬虫等),多线程可以有效提高效率(单线程下的IO操作会等待IO,造成不必要的时间浪费,开启多线程可以节省线程A等待的时间),自动切换到线程B,不浪费CPU资源,从而提高程序执行效率)。所以python的多线程对IO密集型代码比较友好。在python3.x中,GIL没有使用ticks计数,而是使用定时器(执行时间达到阈值后,当前线程释放GIL),对CPU密集型程序比较友好,但还是不行解决GIL导致同一时间只能ticks的问题。能执行一个线程的问题,所以效率还是差强人意。Part04小结回到原题:我们经常听到老手说:“如果要在python下充分利用多核CPU,就用多进程”。是什么原因?原因是每个进程都有自己独立的GIL,互不干扰,真正意义上的并行执行。因此在python中,多进程的执行效率要优于多线程(仅针对多核CPU)。所以我们可以得出一个结论:在多核下,如果想做并行来提高效率,更通用的方法是使用多进程,可以有效提高执行效率。