python的GIL锁优化方案及性能对比

2019-03-19  本文已影响0人  如果仲有听日

网上对于python中的GIL锁的讨论有很多,在工作中发现多线程运行CPU密集型程序时,效率极其低下。现在将python的GIL锁的优化性能对比方案整理如下(GIL锁的原理这里不再累述)

1. 环境和功能描述

在linux下读取一个目录下的20个相同大小的测试文件,将字符串转成json文件重新存储到新的的20个文件中

cpu信息:硬件个数:1, 核心数:16,线程数:32

原始测试文件截图 转换程json格式的文件

2. 单线程顺序执行

耗时1m10s 单个cpu线程使用率100%

2. 多线程效率分析

理论上多线程执行效率应该更高,但实际上效率却成倍减低

同时1线程:1m12s    每运行完一个线程cpu切换

同时2线程:2m7s      2个cpu同时运行不同线程程序,每个cpu使用率70%左右, 每运行完一个线程程序,cpu切换

同时4线程:2m51s    4个cpu同时运行不同线程程序,每个cpu使用率50%左右, 每运行完一个线程程序,cpu切换

同时8线程:2m53s    8个cpu同时运行不同线程程序,每个cpu使用率40%左右, 每运行完一个线程程序,cpu切换

同时16线程:3m10s  16个cpu同时运行不同线程程序,每个cpu使用率20%左右, 每运行完一个线程程序,cpu切换

同时20线程:3m10s   20个cpu同时运行不同线程程序,每个cpu使用率14%左右, 每运行完一个线程程序,cpu切换

效率低下的原因,是因为GIL锁决定了在同一时刻只可能有一个线程在运行程序,当运行的指令数达到一定值的时候才释放GIL锁,给其他线程竞争使用

在这里,就不用线程池做实验了,因为原理是差不多的

3. 优化方案一:进程池

同时20个进程:5s 20个cpu同时运行不同进程程序,每个cpu使用率100%

def logs_to_jsons_of_processing_pool(procId, logFile):

    print '\tStart %d processing [%s]' % (procId, logFile)

    (filepath, tempfilename) = os.path.split(logFile)

    (shotname, extension) = os.path.splitext(tempfilename)

    file_name_output = JSON_MAN_OUTPUT_PATH + shotname + '.json'

    convert_log_to_json(logFile, file_name_output)

    print '\tFinished %d processing [%s]' % (procId, file_name_output)

def load_log_to_json_processing_pool():

    fileList = []

    get_file_list_by_dir(fileList, LOCAL_LOG_PATH_g1, EXT_LOG)

    logCnt = len(fileList)

    print 'file cnt = %d' % logCnt

    fileList.sort()

    pool = multiprocessing.Pool(processes = logCnt)

    for i in range(logCnt):

        pool.apply_async(logs_to_jsons_of_processing_pool, (i, fileList[i]))

    print("%d processes have got!" % logCnt)

    pool.close()

    pool.join()

    print("run finished!")

4. 优化方案二:python中嵌入C代码屏蔽GIL锁

写一个C代码:

部分C代码

将C编译成so动态库文件:

gcc -fPIC logjson.c -shared -o liblogjson.so

python嵌入C代码

同时运行20个C线程:耗时6ms,没错是6个毫秒!

上一篇 下一篇

猜你喜欢

热点阅读