python难度⼤的题_Python最难的问题
Python的底层
要理解GIL的含义,我们需要从Python的基础讲起。像C++这样的语⾔是编译型语⾔,所谓编译型语⾔,是指程序输⼊到编译器,编译器再根据语⾔的语法进⾏解析,然后翻译成语⾔独⽴的中间表⽰,最终链接成具有⾼度优化的机器码的可执⾏程序。编译器之所以可以深层次的对代码进⾏优化,是因为它可以看到整个程序(或者⼀⼤块独⽴的部分)。这使得它可以对不同的语⾔指令之间的交互进⾏推理,从⽽给出更有效的优化⼿段。
与此相反,Python是解释型语⾔。程序被输⼊到解释器来运⾏。解释器在程序执⾏之前对其并不了解;它所知道的只是Python的规则,以及在执⾏过程中怎样去动态的应⽤这些规则。它也有⼀些优化,但是这基本上只是另⼀个级别的优化。由于解释器没法很好的对程序进⾏推导,Python的⼤部分优化其实是解释器⾃⾝的优化。更快的解释器⾃然意味着程序的运⾏也能“免费”的更快。也就是说,解释器优化后,Python程序不⽤做修改就可以享受优化后的好处。
这⼀点很重要,让我们再强调⼀下。如果其他条件不变,Python程序的执⾏速度直接与解释器的“速度”相关。不管你怎样优化⾃⼰的程序,你的程序的执⾏速度还是依赖于解释器执⾏你的程序的效率。这就很明显的解释了为什么我们需要对优化Python解释器做这么多的⼯作了。对于Python程序员来说,这
恐怕是与免费午餐最接近的了。
免费午餐结束了
还是没有结束?摩尔定律给出了硬件速度会按照确定的时间周期增长,与此同时,整整⼀代程序员学会了如何编码。如果⼀个⼈写了⽐较慢的代码,最简单的结果通常是更快的处理器去等待代码的执⾏。显然,摩尔定律仍然是正确的,并且还会在很长⼀段时间⽣效,不过它提及的⽅式有了根本的变化。并⾮是时钟频率增长到⼀个⾼不可攀的速度,⽽是通过多核来利⽤晶体管密度提⾼带来的好处。在新处理器上运⾏的程序要想充分利⽤其性能,必须按照并发⽅式进⾏重写。
⼤部分开发者听到“并发”通常会⽴刻想到多线程的程序。⽬前来说,多线程执⾏还是利⽤多核系统最常⽤的⽅式。尽管多线程编程⼤⼤好于“顺序”编程,不过即便是仔细的程序员也没法在代码中将并发性做到最好。编程语⾔在这⽅⾯应该做的更好,⼤部分应⽤⼴泛的现代编程语⾔都会⽀持多线程编程。
意外的事实
现在我们来看⼀下问题的症结所在。要想利⽤多核系统,Python必须⽀持多线程运⾏。作为解释型语⾔,Python的解释器必须做到既安全⼜⾼效。我们都知道多线程编程会遇到的问题。解释器要留意的是避免在不同的线程操作内部共享的数据。同时它还要保证在管理⽤户线程时保证总是有最⼤化的计算资源。
那么,不同线程同时访问时,数据的保护机制是怎样的呢?答案是解释器全局锁。从名字上看能告诉我们很多东西,很显然,这是⼀个加在解释器上的全局(从解释器的⾓度看)锁(从互斥或者类似⾓度看)。这种⽅式当然很安全,但是它有⼀层隐含的意思(Python初学者需要了解这个):对于任何Python程序,不管有多少的处理器,任何时候都总是只有⼀个线程在执⾏。
许多⼈都是偶然发现这个事实的。⽹上的很多讨论组和留⾔板都充斥着来⾃Python初学者和专家的类似这样的问题——”为什么我全新的多线程Python程序运⾏得⽐其只有⼀个线程的时候还要慢?“许多⼈在问这个问题时还是⾮常犯晕的,因为显然⼀个具有两个线程的程序要⽐其只有⼀个线程时要快(假设该程序确实是可并⾏的)。事实上,这个问题被问得如此频繁以⾄于Python的专家们精⼼制作了⼀个标准答案:”不要使⽤多线程,请使⽤多进程。“但这个答案⽐那个问题更加让⼈困惑。难道我不能在Python中使⽤多线程?在Python这样流⾏的⼀个语⾔中使⽤多线程究竟是有多糟糕,连专家都建议不要使⽤。难道我真的漏掉了⼀些东西?
很遗憾,没有任何东西被漏掉。由于Python解释器的设计,使⽤多线程以提⾼性能应该算是⼀个困难的任务。在最坏的情况下,它将会降低(有时很明显)你的程序的运⾏速度。⼀个计算机科学与技术专业的⼤学⽣新⼿可能会告诉你当多个线程都在竞争⼀个共享资源时将会发⽣什么。结果通常不会⾮常理想。很多情况下多线程都能很好地⼯作,可能对于解释器的实现和内核开发⼈员来说,没有关于Python多线程性能的过多抱怨。
现在该怎么办?惊慌?
那么,这⼜能怎样?问题解决了吗?难道我们作为Python开发⼈员就意味着要放弃使⽤多线程来探索并⾏的想法了?为什么⽆论怎样,GIL 需要保证只有⼀个线程在某⼀时刻处于运⾏中?难道不可以添加细粒度的锁来阻⽌多个独⽴对象的同时访问?并且为什么之前没有⼈去尝试过类似的事情?
这些实⽤的问题有着⼗分有趣的回答。GIL对诸如当前线程状态和为垃圾回收⽽⽤的堆分配对象这样的东西的访问提供着保护。然⽽,这对Python语⾔来说没什么特殊的,它需要使⽤⼀个GIL。这是该实现的⼀种典型产物。现在也有其它的Python解释器(和编译器)并不使⽤GIL。虽然,对于CPython来说,⾃其出现以来已经有很多不使⽤GIL的解释器。
那么为什么不抛弃GIL呢?许多⼈也许不知道,在1999年,针对Python 1.5,⼀个经常被提到但却不怎么理解的“free threading”补丁已经尝试实现了这个想法,该补丁来⾃Greg Stein。在这个补丁中,GIL被完全的移除,且⽤细粒度的锁来代替。然⽽,GIL的移除给单线程程序的执⾏速度带来了⼀定的代价。当⽤单线程执⾏时,速度⼤约降低了40%。使⽤两个线程展⽰出了在速度上的提⾼,但除了这个提⾼,这个收益并没有随着核数的增加⽽线性增长。由于执⾏速度的降低,这⼀补丁被拒绝了,并且⼏乎被⼈遗忘。
移除GIL⾮常困难,让我们去购物吧!
(译者注:XXX is hard. Let's go shopping!在英语中类似于中⽂的咆哮体。其隐含意思为想成功完成某件事情⾮常困难,我们去直接寻第三⽅的产品替代吧。)
不过,“free threading”这个补丁是有启发性意义的,其证明了⼀个关于Python解释器的基本要点:移除GIL是⾮常困难的。由于该补丁发布时所处的年代,解释器变得依赖更多的全局状态,这使得想要移除当今的GIL变得更加困难。值得⼀提的是,也正是因为这个原因,许多⼈对于尝试移除GIL变得更加有兴趣。困难的问题往往很有趣。
但是这可能有点被误导了。让我们考虑⼀下:如果我们有了⼀个神奇的补丁,其移除了GIL,并且没有对单线程的Python代码产⽣性能上的下降,那么什么事情将会发⽣?我们将会获得我们⼀直想要的:⼀个线程API可能会同时利⽤所有的处理器。那么现在,我们已经获得了我们希望的,但这确实是⼀个好事吗?
基于线程的编程毫⽆疑问是困难的。每当某个⼈觉得他了解关于线程是如何⼯作的⼀切的时候,总是会悄⽆声息的出现⼀些新的问题。因为在这⽅⾯想要得到正确合理的⼀致性真的是太难了,因此有⼀些⾮常知名的语⾔设计者和研究者已经总结得出了⼀些线程模型。就像某个写过多线程应⽤的⼈可以告诉你的⼀样,不管是多线程应⽤的开发还是调试都会⽐单线程的应⽤难上数倍。程序员通常所具有的顺序执⾏的思维模恰恰就是与并⾏执⾏模式不相匹配。GIL的出现⽆意中帮助了开发者免于陷⼊困境。
在使⽤多线程时仍然需要同步原语的情况下,GIL事实上帮助我们保持不同线程之间的数据⼀致性问题。
那么现在看起来讨论Python最难得问题是有点问错了问题。我们有⾮常好的理由来说明为什么Python专家推荐我们使⽤多进程代替多线程,⽽不是去试图隐藏Python线程实现的不⾜。更进⼀步,我们⿎励开发者使⽤更安全更直接的⽅式实现并发模型,同时保留使⽤多线程进⾏开发除⾮你觉的真的⾮常必要的话。对于⼤多数⼈来说什么是最好的并⾏编程模型可能并不是⼗分清楚。但是⽬前我们清楚的是多线程的⽅式可能并不是最好的。
⾄于GIL,不要认为它在那的存在就是静态的和未经分析过的。Antoine Pitrou 在Python 3.2中实现了⼀个新的GIL,并且带着⼀些积极的结果。这是⾃1992年以来,GIL的⼀次最主要改变。这个改变⾮常巨⼤,很难在这⾥解释清楚,但是从⼀个更⾼层次的⾓度来说,旧的GIL 通过对Python指令进⾏计数来确定何时放弃GIL。这样做的结果就是,单条Python指令将会包含⼤量的⼯作,即它们并没有被1:1的翻译成机器指令。在新的GIL实现中,⽤⼀个固定的超时时间来指⽰当前的线程以放弃这个锁。在当前线程保持这个锁,且当第⼆个线程请求这个锁的时候,当前线程就会在5ms后被强制释放掉这个锁(这就是说,当前线程每5ms就要检查其是否需要释放这个锁)。当任务是可⾏的时候,这会使得线程间的切换更加可预测。
python新手代码错了应该怎么改
然⽽,这并不是⼀个完美的改变。对于在各种类型的任务上有效利⽤GIL这个领域⾥,最活跃的研究者可能就是David Beazley了。除了对Python 3.2之前的GIL研究最深⼊,他还研究了这个最新的GIL实现,并且发现了很多有趣的程序⽅案。对于这些程序,即使是新的GIL实现,其表现也相当糟糕。他⽬前仍然通过⼀些实际的研究和发布⼀些实验结果来引领并推进着有关GIL的讨论。
不管某⼀个⼈对Python的GIL感觉如何,它仍然是Python语⾔⾥最困难的技术挑战。想要理解它的实现需要对操作系统设计、多线程编程、C语⾔、解释器设计和CPython解释器的实现有着⾮常彻底的理解。单是这些所需准备的就妨碍了很多开发者去更彻底的研究GIL。虽然如此,并没有迹象表明GIL在不久以后的任何⼀段时间内会远离我们。⽬前,它将继续给那些新接触Python,并且与此同时⼜对解决⾮常困难的技术问题感兴趣的⼈带来困惑和惊喜。
以上内容是基于我⽬前对Python解释器所做出的研究⽽写。虽然我还希望写⼀些有关解释器的其它⽅⾯内容,但是没有任何⼀个⽐全局解释器锁(GIL)更为⼈所知。虽然我认为这⾥有些内容是不准确的,但是这些技术上的细节与CPython的很多资源条⽬是不同的。如果你发现了不准确的内容,请及时告知我,这样我就会尽快对其进⾏改正。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论