既然Python解释器是单线程的,还有进行多线程编程的必要吗?

写再多的线程都绕不过解释器是单线程,那不还等于是单线程。且线程切换消耗,既然这样,python还有必要进行多线程编程吗?

8个回答

既然Python解释器是单线程的,还有进行多线程编程的必要吗?
回答

谢小秘书邀请~~

先简单的回答:有必要。

首先,线程消耗的是CPU资源

如果一个单线程内处理的业务逻辑会占用100%的CPU资源,那么,上了多线程也是没有用的。

但这种情况很少,高CPU占用一般出现在内存计算场景下,或者不良代码中错误的死循环。 正常情况下,CPU占用大于80%就需要进行代码或设计的优化,或者服务器增加资源了。

多线程场景适用于解决慢速IO的问题

我们绝大部分的计算,都会依赖于很多外部资源IO,如磁盘读写、网络访问、数据库访问... 这些资源的访问速度远远低于CPU的切换速度。如果使用单线程进行操作时,就会长时间的等待IO的返回。造成无效等待,性能低下。

所以即使是Python,为了充分利用CPU资源,提高性能,在通常的业务场景下使用多线程编程也是完全必要的。

多核与Python多实例

延续上面的问题,我们知道现在CPU大部分都是多核的,python为了避免单线程只能使用到一个核的问题,是有个multiprocessing 库的,允许创建子进程(子进程数一般与核心数相同),来充分利用CPU资源。

↓ ↓ ↓ 喜欢就点赞吧,欢迎各位评论指教,谢谢关注 -- 极迭代

谢邀,我们来聊聊Python的GIL问题。

CPython(标准的python实现)有一个名为GIL(全局解释器锁)的东西,它阻止两个线程在同一个程序中同时执行。 有些人对此感到不安,而其他人则狠狠地为此辩护。 但是,有一些解决方法,像Numpy这样的库通过在C中运行外部代码来绕过这个限制。

何时使用线程与进程?

  • 进程加速了CPU密集型的Python操作,因为它们受益于多个内核并避免使用GIL。

  • 线程最适合IO任务或涉及外部系统的任务,因为线程可以更有效地组合他们的工作。 进程需要挑选他们的结果来组合它们需要时间。

由于GIL,线程在python中没有为CPU密集型任务提供任何好处。而对于像Dot Product这样的某些操作,Numpy可以解决Python的GIL并且并行执行代码。

I/O的多线程使用

应用程序的大部分时间都花在I/O上。无论是磁盘I/O还是网络I/O。

例如,对于Web应用程序,大多数情况下是处理数据库。因此,在大多数现代应用程序中,最大的瓶颈是I/O。以下是开启4个线程后效果,实际上效果还是很显著的。

这意味着应用程序大部分都在等待,因此即使python没有GIL,也不是所有应用程序都会一直运行(使用cpu,因为它们将等待I/O完成)。

所以,在大多数应用程序线程在I / O上等待的情况下,其他线程可以获取CPU,从而提高性能。如果python没有多线程,那么其他一些线程无法获得cpu因此浪费时间。现在至少当一个线程正在等待I/O时(大部分应用程序都是这种情况),其余的线程都可以工作,那么多线程还是有它存在的必要,所以这就是我们没有看到GIL所拥有问题的原因。

当然如果你的应用程序是CPU密集型的,那么在python中确实没有太多的线程可以提供使用。


我会在这里发布所有与科技、科学有关的有趣文章,欢迎订阅我的头条号。偶尔也回答有趣的问题,有问题可随时在评论区回复和讨论。

(码字不易,若文章对你帮助可点赞支持~)

展开全部
刚好,在整理关于对Python GIL的理解,正好可以回答这个问题,贴一下。


GIL 的存在一直是富有争议的,它导致 Python 程序无法真正利用现代操作系统的多进程特性。需要注意的是,对于 I/O 图形处理、NumPy 数学计算这样的耗时操作都发生在 GIL 之外,实际上基本不受影响,真正受影响的都是 Python 字节码的执行,GIL 会导致性能瓶颈的出现。总之,只有在使用纯 Python 做 CPU 密集的多线程运算时 GIL 会是问题。

GIL是什么

Python的代码执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,Python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行。即每个CPU在任意时刻只有一个线程在解释器中运行。对python虚拟机访问的控制由全局解释锁GIL控制,正是这个锁来控制同一时刻只有一个线程能够运行。——(在单核CPU下的多线程其实都只是并发,不是并行) 。

并发与并行区别

  • 并发:两个或多个事件在同一时间间隔发生,或者说交替做不同事件的能力,或者说不同的代码块交替执行。
  • 并行:两个或者多个事件在同一时刻发生,或者说同时做不同事件的能力,或者说不同的代码块同时执行。

并发和并行的意义:

并发和并行都可以处理“多任务”,二者的主要区别在于是否是“同时进行”多个的任务。

但是涉及到任务分解(有先后依赖耦合度高的任务无法做到并行)、任务运行(可能要考虑互斥、锁、共享等)、结果合并。


python 下的多线程

在Python多线程下,每个线程的执行方式:

  1. 获取GIL
  2. 切换到这个线程去执行
  3. 运行代码
  4. 把线程设置为睡眠状态
  5. 释放GIL
  6. 再次重复以上步骤

在Python2中,在解释器解释执行任何 Python 代码时,都需要先获得这把锁才行(同一时间只会有一个获得了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放),在遇到 I/O 操作时会释放这把锁。如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100 次操作就释放这把锁,让别的线程有机会执行(这个次数可以通过 sys.setcheckinterval 来调整)也正是这种设定,是的多线程的CPU密集型计算非常鸡肋,下面会讲到为何如此。

而在python3中,GIL不使用ticks计数(100次,释放GIL),改为使用计时器(执行时间达到15ms阈值后,当前线程释放 GIL),使得执行计算的次数更多,释放次数减少,这样对CPU密集型程序更加友好,但依然没有解决GIL导致的同一时间只能执行一个线程的问题,所以效率依然不尽如人意。


那么是不是python的多线程是鸡肋嘛?

CPU密集型(各种循环处理、计数等等),在这种情况下,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换是需要消耗资源的),所以python下的多线程对 CPU密集型代码并不友好,会触发相当频繁的线程切换。

IO密集型(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO 等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费 CPU的资源,从而能提升程序执行效率,一个线程获得GIL发送消息,然后等待返回消息(阻塞),Python此时释放GIL, 其他线程得到GIL发送消息,然后同样等待返回消息(阻塞)......,这样保证了IO传输过程时间的合理利用,减少了IO等待造成的资源浪费,提高IO传输效率)。所以python的多线程对IO密集型代码比较友好。


结论

I/O密集型使用多线程并发执行提高效率、计算密集型使用多进程(multiprocessing )并行执行提高效率。通常程序既包含IO操作又包含计算操作,那么这种情况下,在开始并发任务之前,可以先进行测试,测试多线程、多进程哪个效率高就是用哪种方式。

请注意:多核多线程比单核多线程更差,多核多进程下,CPU1释放GIL后,其他CPU上的线程都会进行竞争,但GIL可能会马上又被CPU1拿到,CPU2释放GIL后……,导致其他几个CPU上被唤醒后的线程会醒着等待到切换时间后又进入待调度状态,这样会造成线程颠簸(thrashing),导致效率更低。

多线程下的CPU密集型计算也不是无药可医,可以利用ctypes绕过GIL,ctypes可以使py直接调用任意的C动态库的导出函数。所要做的只是把关键部分用 C/C++ 写成 Python 扩展。而且,ctypes会在调用C函数前释放GIL。


同时,可以了解下协程,又称微线程。

协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。


转载请说明出处,若多你有帮助点赞支持哦。

出自本人头条号文章《鸡肋?Python中的多线程与多进程那些事》,文章链接:https://www.toutiao.com/i6623325333112226311/
展开全部

更多阅读

正在为您加载更多

问答青云计划自荐标准: