使用进程池规避Python的GIL限制

操作系统 : CentOS7.3.1611_x64

python版本:2.7.5

问题描述

Python的GIL会对CPU密集型的程序产生影响,如果完全使用Python来编程,怎么避开GIL的限制呢?

解决方案

在多线程中使用进程池来规避GIL的限制。具体如下:

1、使用multiprocessing模块来创建进程池;

2、将计算任务分配给不同的线程;

3、在任务线程中把任务提交给之前创建的进程池;

每当有线程要执行cpu密集型任务时,就把该任务提交到进程池中,然后进程池会将任务交给运行在另一个进程中的Python解释器。

当线程等待结果时会释放GIL,而此时的计算任务是在另一个单独的Python解释器中执行的,不再受到GIL的限制了。

在多核系统中采用这个方案能轻易地利用到所有的CPU核心。

假设有这样的worker函数:

def worker(arr):
    s = 0
    for n in arr :
        arrTmp = range(1,n+1)
        if len(arrTmp) == 0 : continue
        rtmp = 1
        for i in arrTmp :
            rtmp *= i
        s += rtmp
    return s

完整代码如下:https://github.com/mike-zhang/pyExamples/blob/master/gilAvoid/gilAvoidTest1/taskCommon.py

普通单进程任务实现:

def main():
    s = 0
    tStart,tStop = 1,1000
    for i in range(1,100):
        #t = worker(range(tStart,tStop))
        t = worker(range(1,1000))
        s += t
        tStart = tStop
        tStop += 1000
    print("len : ",len(str(s)))
    print(s%10000)

完整代码如下: https://github.com/mike-zhang/pyExamples/blob/master/gilAvoid/gilAvoidTest1/t1_normal.py

运行效果如下:

(py27env) [[email protected] test]$ time python t1_normal.py
(‘len : ‘, 2567)
987

real    0m17.919s
user    0m17.915s
sys     0m0.003s

使用进程池的实现:

def wokerThread(start,stop):
    #r = gPool.apply(worker,(range(start,stop),))
    r = gPool.apply(worker,(range(1,1000),))
    q.put(r)

def main():
    s = 0
    thrdArr = []
    tStart,tStop = 1,1000
    for i in range(1,gCount+1):
        thrd = threading.Thread(target=wokerThread,args=(tStart,tStop))
        thrdArr.append(thrd)
        tStart = tStop
        tStop += 1000
    for t in thrdArr :
        t.daemon = True
        t.start()
    while not q.full(): time.sleep(0.1)
    while not q.empty(): s += q.get()
    print("len : ",len(str(s)))
    print(s%10000)

完整代码如下:https://github.com/mike-zhang/pyExamples/blob/master/gilAvoid/gilAvoidTest1/t2_mp.py

运行效果如下:

(py27env) [[email protected] test]$ time python t2_mp.py
queue full
(‘len : ‘, 2567)
987

real    0m4.917s
user    0m18.356s
sys     0m0.146s

可以看出使用上述方法可以规避GIL的限制(测试机器为i5 4核),程序的速度得到明显的提升。

好,就这些了,希望对你有帮助。

本文github地址:

https://github.com/mike-zhang/mikeBlogEssays/blob/master/2017/20170819_使用进程池规避python的GIL限制.rst

欢迎补充

时间: 2024-08-11 09:42:27

使用进程池规避Python的GIL限制的相关文章

GIL 线程池 进程池 同步 异步

1.GIL(理论 重点)2.线程池 进程池3.同步 异步 GIL 是一个全局解释器锁,是一个互斥锁 为了防止竞争解释器资源而产生的 为何需要gil:因为一个python.exe进程中只有一份解释器,如果这个进程开启了多个线程 都要执行代码 多线程之间要竞争解释器 一旦竞争就有可能出现问题 带来的问题:同一时间只有一个线程可以访问解释器 好处:保证了多线程的数据安全 thread-safe 线程安全的 多个线程同时访问也不会出问题 not thread-safe 非线程安全的 多个线程同时访问可能

4月27日 python学习总结 GIL、进程池、线程池、同步、异步、阻塞、非阻塞

一.GIL:全局解释器锁 1 .GIL:全局解释器锁 GIL本质就是一把互斥锁,是夹在解释器身上的, 同一个进程内的所有线程都需要先抢到GIL锁,才能执行解释器代码 2.GIL的优缺点: 优点:  保证Cpython解释器内存管理的线程安全 缺点:同一进程内所有的线程同一时刻只能有一个执行,也就说Cpython解释器的多线程无法实现并行 二.GIL与多线程 有了GIL的存在,同一时刻同一进程中只有一个线程被执行 听到这里,有的同学立马质问:进程可以利用多核,但是开销大,而python的多线程开销

python GIL锁、进程池与线程池、同步异步

一.GIL全局解释器锁 全局解释器锁 在CPython中,全局解释器锁(GIL)是一个互斥锁,它可以防止多个本机线程同时执行Python代码.之所以需要这个锁,主要是因为CPython的内存管理不是线程安全的.(然而,自从GIL存在以来,其他特性已经逐渐依赖于它所执行的保证) 什么是GIL 全局解释器锁, 施加在解释器上的互斥锁 为什么需要GIL 由于CPython的内存管理时非线程安全,于是CPython就给解释器加上锁, 解决了安全问题. GIL的加锁与解锁时机 加锁的时机: 在调用解释器时

python第三十七天,GIL全局解释器锁*****,线程池与进程池 同步异步,阻塞与非阻塞,异步回调

GIL全局解释器锁 1.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe

Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池

目录 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 2.死锁现象与递归锁 2.1死锁现象 2.2递归锁 3.信号量 4.GIL全局解释器锁 4.1背景 4.2为什么加锁 5.GIL与Lock锁的区别 6.验证计算密集型IO密集型的效率 6.1 IO密集型 6.2 计算密集型 7.多线程实现socket通信 7.1服务端 7.2客户端 8.进程池,线程池 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 #生产者消

python进程池剖析(一)

python中两个常用来处理进程的模块分别是subprocess和multiprocessing,其中subprocess通常用于执行外部程序,比如一些第三方应用程序,而不是Python程序.如果需要实现调用外部程序的功能,python的psutil模块是更好的选择,它不仅支持subprocess提供的功能,而且还能对当前主机或者启动的外部程序进行监控,比如获取网络.cpu.内存等信息使用情况,在做一些自动化运维工作时支持的更加全面.multiprocessing是python的多进程模块,主要

27 Apr 18 GIL 多进程多线程使用场景 线程互斥锁与GIL对比 基于多线程实现并发的套接字通信 进程池与线程池 同步、异步、阻塞、非阻塞

27 Apr 18 一.全局解释器锁 (GIL) 运行test.py的流程: a.将python解释器的代码从硬盘读入内存 b.将test.py的代码从硬盘读入内存  (一个进程内装有两份代码) c.将test.py中的代码像字符串一样读入python解释器中解析执行 1 .GIL:全局解释器锁 (CPython解释器的特性) In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple na

GIL全局解释器锁和进程池.线程池

GIL全局解释器锁 GIL本质就是一把互斥锁,是夹在解释器身上的,同一个进程内的所有线程都需要先抢到GIl锁,才能执行解释器代码 GIL的优缺点: 优点:保证Cpython解释器内存管理的线程安全 缺点:同一个进程内所有的线程同一时刻只能有一个执行,也就是说Cpython解释器的多线程无法实现并行,无法取得多核优势 GIL与单线程 每个进程的内存空间中都有一份python解释器的代码,所以在单线程的情况下,GIL锁没有线程争抢,只有垃圾回收机制线程会定时获取GIL权限 GIL与多线程 有了GIL

第36篇 多进程的数据共享,进程池的回调函数,线程 什么是GIL锁,Threading模块记

内容概览: 进程 数据共享 进程池--回调函数 线程 线程的基础理论 什么是线程? 线程与进程的关系 GIL锁 线程的开启: Threading模块1,用多进程开启socket创建聊天 server端写了input函数会报错?因为服务器是高速运行的,自动化的为来访问的客户端提供服务, 不可能停下来等待管理员的输入,然后发送给客户.这就失去了自动化的意义. 2,进程池Pool()方法创建的进程,map()方法是否有返回值? p.map()得到的是迭代对象 import time from mult