python GIL锁问题

学习内容来源于《流畅的python第17章内容》,我觉得讲的挺清楚的

CPython 解释器本身就不是线程安全的, 因此有全局解释器锁(GIL)确保线程操作安全 ,
所以一次只允许使用一个线程执行 Python 字节码。 因此, 一个 Python 进程通常不能同时使用多个 CPU 核心。
这是 CPython 解释器的局限, 与 Python 语言本身无关。 Jython 和 IronPython 没有这种限制。
不过, 目前最快的Python 解释器 PyPy 也有 GIL。

然而, 标准库中所有执行阻塞型 I/O 操作的函数, 在等待操作系统返回结果时都会释放 GIL。 这意味着在 Python 语言这个层次上可以使用多线程, 而 I/O 密集型 Python 程序能从中受益: 一个 Python 线程等待网络响应时, 阻塞型 I/O 函数会释放 GIL, 再运行一个线程。
Python 标准库中的所有阻塞型 I/O 函数都会释放 GIL, 即标准库中每个使用 C 语言编写的 I/O 函数都会释放 GIL, 因此, 当某个线程在等待 I/O 时, Python 调度程序会切换到另一个线程,允许其他线程运行。 time.sleep() 函数也会释放 GIL。 因此, 尽管有GIL, Python 线程还是能在 I/O 密集型应用中发挥作用。

也就是说 python多线程 :
在I/O密集型时,是可以使用的,此时无GIL锁。
在CPU密集型时,只有一个线程运行,此时只能使用一个CPU ,有GIL所锁

在 CPU 密集型作业中使用 concurrent.futures 模块中的 ProcessPoolExecutor可以轻松绕开 GIL
使用 ProcessPoolExecutor 类把工作分配给多个Python 进程处理。
因此, 如果需要做 CPU 密集型处理, 使用这个模块能绕开 GIL, 利用所有可用的 CPU 核心
如果使用 Python 处理 CPU 密集型工作, 应该试试PyPy解释器

在I/O 密集型作业中使用concurrent.futures 模块中的ThreadPoolExecutor 可以进行多线程任务执行
Python 线程特别适合 I/O 密集型应用, concurrent.futures 模块大大简化了某些使用场景下 Python 线程的用法。

如果concurrent.futures包 并不能满足你的简单任务需求,我们可以使用multiprocessing,threading 利用里面的各种组件来完成我们复杂的需求

其实ProcessPoolExecutor/ThreadPoolExecutor 是封装了multiprocessing/threading 里面的各种组件,使我们能够方便的使用,的确很方便。也就是我们通常所说的concurrent.futures并发包,它们的成员方法接口都一样,方便我们不需要注意太多内部实现细节,即可实现多进程、多线程任务的并发操作。

Executor.map 函数易于使用, 不过有个特性可能有用, 也可能没用,
具体情况取决于需求: 这个函数返回结果的顺序与调用开始的顺序一
致。 

executor.submit 和 futures.as_completed 这个组合比executor.map 更灵活,
因为 submit 方法能处理不同的可调用对象和参数,
而 executor.map 只能处理参数不同的同一个可调用对象。
此外, 传给 futures.as_completed 函数的期物集合可以来自多个 Executor 实例,
例如一些由 ThreadPoolExecutor 实例创建, 另一些由 ProcessPoolExecutor 实例创建。

并发是指一次处理多件事。
并行是指一次做多件事。
二者不同, 但是有联系。
一个关于结构, 一个关于执行。
并发用于制定方案, 用来解决可能(但未必) 并行的问题

真正的并行需要多个核心
现代的笔记本电脑有4 个 CPU 核心, 但是
通常不经意间就有超过 100 个进程同时运行。 因此, 实际上大多数过程
都是并发处理的, 而不是并行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值