多进程(multiprocessing)

2020年5月30日 / 27次阅读 / Last Modified 2020年5月30日
多进程

python标准库中有一个多进程模块,multiprocesing,它可以支持在代码创建多个进程协同运行的计算模型,此模块很多接口名和参数,都与多线程一致。

从代码上看多进程,依然是给进程指定一个函数作为入口,python底层自动启动一个独立进程从此入口开始执行。如果是GUI程序,多进程可以更好的实现多个tkinter的root窗口。

为什么要多进程?

CPython解释器中的GIL,限制了多线程无法充分利用多CPU资源,因此有了多进程的用武之地。如果IO密集型的任务,多线程就可以了。如果是计算密集型的任务,有多个CPU时,就要考虑多进程,以充分利用资源。

GIL (Global Intercepto Lock)全局解释器锁

首先需要明确的一点是 GIL 并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。

并行和并发

并行和并发同属于多任务,目的是要提高CPU的使用效率。这里需要注意的是,一个CPU永远不可能实现并行,即一个CPU不能同时运行多个程序,但是可以在随机分配的时间片内交替执行(并发),就好像一个人不能同时看两本书,但是却能够先看第一本书半分钟,再看第二本书半分钟,这样来回切换。

Guido van Rossum(吉多·范罗苏姆)创建python时就只考虑到单核cpu,解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁,于是有了GIL这把超级大锁。因为cpython解析只允许拥有GIL全局解析器锁才能运行程序,这样就保证了保证同一个时刻只允许一个线程可以使用cpu。由于大量的程序开发者接收了这套机制,现在代码量越来越多,已经不容易通过C代码去解决这个问题。

每个线程在执行时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU,也就是说多线程并不是真正意义上的并行执行。

多线程如同客人要用包房里的厕所,一次只能一个人用。进去的人把门锁住。用完释放,下一个人接着用。进程如同独立包房,一个厕所够了,不需要排队,也就不需要锁了。

那么,我们改如何解决GIL锁的问题呢?
1.更换cpython为jpython(不建议)
2.使用多进程完成多线程的任务
3.在使用多线程可以使用c语言去实现

问题1: 什么时候会释放Gil锁?
答 :
1 遇到像 i/o操作这种 会有时间空闲情况 造成cpu闲置的情况会释放Gil
2 会有一个专门ticks进行计数 一旦ticks数值达到100 这个时候释放Gil锁 线程之间开始竞争Gil锁(说明:ticks这个数值可以进行设置来延长或者缩减获得Gil锁的线程使用cpu的时间)
问题2: 互斥锁和Gil锁的关系
Gil锁 : 保证同一时刻只有一个线程能使用到cpu
互斥锁 : 多线程时,保证修改共享数据时有序的修改,不会产生数据修改混乱
GIL与多线程
  有了GIL的存在,python有这两个特点:
    1、进程可以利用多核,但是开销大。
    2、多线程开销小,却无法利用多核优势。
也就是说Python中的多线程是假的多线程,Python解释器虽然可以开启多个线程,但同一时间只有一个线程能在解释器中执行,而做到这一点正是由于GIL锁的存在,它的存在使得CPU的资源同一时间只会给一个线程使用,而由于开启线程的开销小,所以多线程才能有一片用武之地,不然就真的是鸡肋了。

而python的多线程到底有没有用,我们需要看任务是I/O密集型,还是计算密集型:如果是I/O密集型任务,有再多核也没用,即能开再多进程也没用,所以我们利用python的多线程一点问题也没有;如果是计算密集型任务,我们就直接使用多进程就可以了。

-- EOF --

本文链接:https://www.pynote.net/archives/2014

留言区

《多进程(multiprocessing)》有4条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    并发,concurrent,并行,parallel [回复]

  • 麦新杰

    多核CPU,就可以利用python多进程的特性,实现并行。线程是CPU的调度单位,属于不同进程的线程可以同时在不同的CPU核上运行。 [回复]

  • 麦新杰

    【如何绕过GIL?】 有了多进程后,大部分程序都可以通过多进程的方式绕过GIL ,但如果依旧不满足,就需要使用C/C++来实现这部分代码,并生成对应的so或dll文件,再通过Python的ctypes将其调用起来 ,Python中很多对计算性能有较高要求的库都采用了这种方式,如Numpy、Pandas等等 。 如果你对程序的性能要求的特别严格,此时更好的方法是选择其他语言 。 [回复]

  • 麦新杰

    Python中的线程工作一段时间后,会主动释放GIL,这是为了让其他线程都有机会执行 ,而释放的时机就涉及到了「检查间隔」(check interval)机制 ,在早期版本的Python中,检查机制是100ticks,而Python3后,每隔5毫秒使用一次检查间隔 。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top