[翻译作品]PEP 518——指定构建Python项目的最低系统要求

注:PEP = Python Enhancement Proposal (Python增强建议书,即Python开发规范) 摘要 本PEP详细说明了Python软件包要在选定的构建(Build)系统上运行时,应该如何指定其依赖关系。本规范引入了一个新的配置文件,用于指定软件包的构建依赖关系(假定今后的配置会使用相同的配置文件作为参考)。 基本原理 当Python首次开发用于构建项目软件分发的工具时,distutils [1]是选定的解决方案。随着时间的推移,setuptools [2]越来越流行,它在distutils的基础上增加了一些功能。两者都应用了setup.py文件这样一个概念。项目维护人员通过执行这个文件来构建其软件的发行版(使得用户也能够安装上述发行版)。 distutils是Python标准库的一部分,所以,使用一个可执行文件来指定distutils下的构建条件是没有问题的。将构建工具作为Python的一部分意味着,项目维护人员如果要构建一个项目的发行版,无需担心setup.py有哪些外部依赖项。唯一的依赖项只是Python,因此没有必要指定任何依赖信息。 但是当一个项目选择使用setuptools时,像setup.py这样的可执行文件的使用就成了一个问题。你无法在不知道setup.py文件依赖关系的条件下执行它。可是,目前还没有标准的方法,在不执行存储着依赖信息的setup.py文件的情况下,自动地了解它具体有哪些依赖项。这就形成了一个悖论:你不运行这个文件,你就无法知道它的内容;你不知道这个文件的内容,就无法运行它。 setuptools尝试用它的setup() 函数的setup_requires参数来解决这个问题[3]。 此解决方案有许多问题,例如: 除了setuptools本身,没有工具可以在不执行setup.py的情况下访问这些信息,但是如果不安装这些项目,setup.py将无法执行。 尽管setuptools本身会安装setup.py中列出的一切,但在执行setup() 函数期间,它们将不会被安装,这意味着实际使用此处添加的任何东西的唯一方法是通过越来越复杂的机制来延迟导入和使用,直到后来执行setup() 函数为止。 该方案不包括setuptools本身,也不能包括setuptools的替代品,这意味着像numpy.distutils这样的项目很大程度上无法利用它,项目不能利用较新的setuptools功能,直到用户自然地将setuptools的版本升级到较新的版本。 setup_requires中列出的项目只要执行setup.py就会被安装,但执行setup.py的常见方式是通过另一个工具,比如已经负责管理依赖关系的pip。 这意味着像pip install spam这样的命令可能最终导致pip和setuptools下载和安装软件包,最终,用户需要配置这两个工具(并且不受控制调用的setuptools)来更改它安装的存储库等设置。 这也意味着用户需要了解这两种工具的发现规则,因为每个工具可能支持不同的软件包格式或以不同方式确定最新版本。 这导致了setup_requires很少被人使用的情况,在这种情况下,项目倾向于只是在多个setup.py文件之间复制和粘贴代码片段,或者完全跳过,仅仅只在某个地方记录好–希望用户在尝试建立或安装他们的项目之前,已经手动安装好的内容。 所有这一切使得pip [4]假定在执行setup.py文件时setuptools是必需的。但问题在于,如果另一个项目像setuptools那样开始在社区中获得关注,这个项目就没有可扩展性。如此一来,会阻止其他项目获得应有的关注。因为当pip无法推断出项目需要的是除setuptools以外的某个东西时,使用setuptools便会产生冲突。 本PEP试图在特定文件中、以一种声明式的方式显式列出项目构建系统的最小依赖关系,从而解决当前的状况。此举允许项目列出它必须具有何种构建依赖关系。例如,源代码签出到wheel,同时不落入setup.py所形成的悖论中。即,工具无法推断项目需要自行构建的东西。实施本PEP将允许项目预先指定他们依赖的构建系统,以便像pip这样的工具可以确保所有依赖条件已经安装,以便运行构建系统来进行构建。 为了提供更多的上下文和推动本PEP,可以把所需的(大体)步骤看成是生成一个手工项目的过程: 项目的源代码签出 构建系统的安装 构建系统的运行 本PEP涵盖了第2步。 预计未来的PEP将包括第3步,包括如何使构建系统动态指定构建系统执行其工作所需的更多依赖性。 但是,本PEP的目的是为构建系统指定要开始运行所需的最低要求。 规范 构建系统的依赖关系将存储在一个名为pyproject.toml的文件中,该文件以TOML格式编写[6]。选择这种格式是因为它可供人来使用(不像JSON [7]),它足够灵活(不像configparser [9])起源于某个标准(也不像configparser [9]),不过于复杂(不像YAML [8])。 TOML格式已被Rust社区用作其包管理器的一部分[14],据私人电邮所述,他们对选择TOML感到非常满意。关于为什么不选择各种替代品的更详细的讨论可以阅读以下其他文件格式的部分。 在配置文件中将会有一个[build-system]表来存储与构建相关的数据。最初,表中只有一个关键字是有效的和必需的:requires。该键将包含一个字符串列表的值,代表执行构建系统所需的PEP 508依赖体哦阿健(意味着执行setup.py文件需要哪些依赖条件)。 以下的JSON架构[15]将与数据格式匹配,表示了某个特定类型的结果数据。这些数据来自于仅供演示用的TOML文件: 对于绝大多数依赖setuptools的Python项目,pyproject.toml文件会是这个样子: [build-system] # Minimum requirements for the […]

[翻译作品]数字背后的故事:Python社区2017/2018年发展趋势

本文透过大量收集自Python开发者调查的数据,揭示了有关Python编程语言的最新使用情况和发展轨迹。 Python正变得越来越受欢迎,在科技新闻中引起了人们更多的关注。有报道说,更多的女高中生们正在将Python应用于计算机工程的学习;Python被推荐为大学计算机入门课程的编程语言。 此外,Stack Overflow的2018年开发者调查显示,Python是大多数人想学习的编程语言。 Python被广泛用于网络,从简单的个人网站,到全世界大型银行里的数据挖掘和机器学习。 是什么让Python如此特别? Python开发者是哪些人? 它为什么如此受欢迎? 为了回答这些以及其他许多重要的问题,JetBrains和Python软件基金会(Python Software Foundation,PSF)合作,针对使用Python作为主要或次要语言的人群开展了一项调查。 到目前为止,还没有人做过针对Python的专项研究,以期了解不同开发人员是如何使用它的,有哪些组件促进了它的使用,以及是什么让它成为了最受欢迎的语言之一。 我们调查的目标是确定Python的最新趋势,并一窥Python开发界的全貌。抱着这一目的,我们着手研究了以下问题: Python 3最新的普及率是多少? Python是怎样和其他语言一起使用的? 什么样的项目会用到Python? Python用户的主要开发类型有哪些? 最流行的技术和工具是什么? 最常见框架和库有哪些,以及它们是如何相辅相成的? Python开发者是一群什么样的人? 该调查于2017年10月发布。这里是我们对结果所做的汇总,你也可以从Python开发者调查2017年结果的网站上挖掘更多的图表和原始数据。 方法论 在我们查看相关数据和见解之前,有必要回顾一下调查所采取的方法,包括:调查是如何派发的,采取了哪些措施来避免潜在的偏见,并确保调查不倾向于任何特定的工具,技术,库,或者国家。 我们将调查发送给几个独立的团体,包括订阅了PSF邮件列表,博客,Slack,LinkedIn和Twitter的人员。我们还在一些访问量最大的Python.org页面上推广了该项调查,并通过阅读文档进行了公布。大部分回复(62%)来自Python.org上的广告横幅;其他主要来源是PSF博客和Twitter帖子。我们没有利用产品、服务或供应商相关的渠道,以防止调查结果倾向于任何特定的工具或技术。 调查深受社区的欢迎,回复率超过预期。在开放期间,收到的回复超过了1万份。我们在做调查分析时过滤掉了不完整和重复的回复,留下来的数据集包括了来自150多个国家的9,532名应答者。对于如此大的样本,描述统计误差的保守置信区间仅为1%,意味着所有结果都具有统计显著性。我们实现了调查的主要目标:收到了准确可靠的数据! Python开发者画像 开启Python世界之旅的第一步,让我们来聊聊最令人兴奋的事儿 — 和Python语言及其应用程序相比,Python社区也呈现出同样的多元化。 虽然Python用户的年龄范围很广,但是大多数受访者的年龄在20岁左右,四分之一在30多岁。有趣的是,几乎五分之一的Python用户年龄在20岁以下。如果我们将Python开发人员的年龄范围,与Stack Overflow在其最新调查中确定的一般开发人员的年龄范围进行比较,分布情况比较相似。区别在于,Python调查中,年龄在18岁以下的开发者稍微多一些。原因在于,很多中学和大学的学生在使用Python,而且Python常常被选作第一门语言。 超过一半的受访者是全职的开发人员,每五名开发人员中就有一位担任数据分析师,架构师,或团队负责人。与Stack Overflow的调查相比,我们可以看到:Python开发者比一般开发者更少可能全职工作(52%的Python开发人员与74%的开发人员),更有可能为自己工作,或成为自由职业者(Python开发人员占13%,所有开发人员占9.7%)。 Python调查的受访者呈现出各种不同的经验; 22%的人拥有不到一年的经验,超过11年经验的人也是这个比例,而在这两者之间的分布趋于平滑。这表明新手和经验丰富的开发人员之间保持了良好的平衡,使Python成为了可持续发展的语言。 值得注意的是,Python比其他语言的平均新手比例高得多。 根据Stack Overflow数据,30%的开发人员拥有不到两年的专业经验,而Python开发人员调查中的这一比例为41%。 大型的Python开发团队中并不多见。 在我们的调查中,56%的Python开发人员表示他们独立开发项目,40%的人通常在2到7人的团队中工作。 大约一半的受访者在从事一个主要项目的同时还有几个小项目,而四分之一的人则一次只从事一个项目。 2016年,JetBrains在没有PSF参与的情况下举办了一次Python开发者调查。 虽然JetBrains在2016年的样本规模很大,但其调查主要通过自己的渠道进行推广,这自然吸引了PyCharm用户中的更大份额 – 约50%的PyCharm用户和50%的使用其他编辑器的用户。 为了减少不可避免的偏差,2016年的调查没有比较不同代码编辑器的用户数量。 尽管2016年的调查结果存在偏差,仍然值得比较一下2017年和2016年的一些调查结果。 例如,在2016年的调查中,45%的人表示独立完成自己的项目,51%的人则是团队工作。 2017年调查中的这一比例不同也许是因为,有大量的新手,且Python是他们的第一语言,以及数据科学家的数量和现在使用Python的Web开发者的数量旗鼓相当。 Python工作机会 正如我们上面所写的,在Stack Overflow的2018年开发者调查中,Python是最理想的语言(即调查者最有兴趣学习的语言);这是Python连续第二年获得该排名。 Python用户在排名最高的编程语言中排名第三。这些事实与Python就业市场是什么关系呢? 尽管Python开发人员调查并未专门提出工作受欢迎度,但我们可以从Python开发人员需要的其他资源中,收集世界范围内的各种工作信息。包括机器学习,数据库,数据分析,云基础设施,设计,站点可靠性/测试,网络抓取,安全性,移动开发,API等等。根据jobs.python.org上列出的职位,机会倾向于国际化需求,尤其是在英国地区。 […]

[翻译作品]Python ipaddress 模块之概述

原文地址:https://dbader.org/blog/python-ipaddress-module 作者:Jon Crawfurd 副标题:本文介绍了Python 3.3以上版本中用于处理IPv4和IPv6地址的ipaddress模块。 在本文中,我们会看一看Python 3.3及更高版本中提供的ipaddress模块。 本教程旨在为想知道如何在Python中解析和使用IP地址的网络工程师们提供一个简要参考。 在这篇概述中,你将了解到: IPv4和IPv6地址之间的区别是什么 如何使用Python的ipaddress模块处理IPv4地址 如何使用Python的ipaddress模块处理IPv6地址 IPv4与IPv6地址 – 入门知识 从大的方面来说,IPv4地址和IPv6地址具有相同的目的和功能。但是,由于每个协议的地址结构存在很大差异。本教程用了不同的部分,来分别讨论IPv4和IPv6。 当今的互联网中,IPv4协议承担了绝大部分的IP处理任务,在不久的将来也依旧如此。 尽管IPv6所带来的规模和功能方面的增强对未来互联网不可或缺,正在被逐步应用,但是到目前为止,应用率仍然很低。 一个IPv4地址由32位组成,分为四个“八位组”。 “八位组”一词用于标识一个八位结构来代替更常见的术语“字节”,但它们的定义相同。四个八位组被称为octet1,octet2,octet3和octet4。这是一个“点分十进制”格式,其中每个八位组对应一个从0到255的十进制值。 IPv4地址示例:192.168.100.10 IPv4地址示例(CIDR表示法):192.168.100.10/24 “/24”是CIDR表示法,表示32位的前24位用于标识地址的网络部分。 记住每个八位组长度为8位,这意味着前三个字节(3×8 = 24)标识网络(192.168.100.x),地址的其余八位标识节点(x.x.x.10)。 CIDR表示法可以是从 /8位 到 /30位的任何值,偶尔有 /32位(/31无效),但通常使用/24。 例如,你的家庭网络,或你的学校或公司网络很可能用/24 CIDR来表示。 用于表示网络标识的早期术语是子网掩码,其中CIDR表示为单独的点分十进制数。 例如,一个/24 CIDR相当于一个网络掩码255.255.255.0。 IPv6地址长度为128位,与IPv4地址中的32位相比,有显著的增加。 IPv4和IPv6之间有很多不同之处,但最大的区别在于寻址结构。 额外的长度提供了可支持的网络和主机数量的指数级增长。 IPv6地址示例:2001:db8:abcd:100::1/64 在IPv4地址使用点分十进制格式的情况下,IPv6协议使用十六进制表示法。 IPv6地址中的每个位置表示4个位,其值从0到f,按以下方式组织: 128位被分成8组,每组16位,每组由冒号分隔。一个组被称为4个十六进制字符(4个十六进制字符乘以4位= 16位)的“四重组”或“十六位组”。在上面的例子中,第一个四重组是“2001”。 任何四重组中的头部的0会被去除/压缩。在上面的例子中,第二个四重组是“db8”,实际上是“0db8”“,最开头的0被去掉了。最后一个四重组是“1”,实际上是“0001”“,三个头部0被压缩了。 如果一个四重组包含全零,它将被压缩为一个零。例如:具有“:0000:”的四重组将被压缩为“:0:”。 如果一个地址包含一个连续的全部为零的四重组,则连续的零被压缩并用双冒号表示。在上面的例子中,双冒号表示3个全部为零的四重组,或者“:0000:0000:0000:”浓缩为“::”。由于范例的地址有5个有值的四重组,所以压缩以后的四重组的数量肯定是3个(总数减8)。 所有的IPv6地址结构都使用CIDR表示法来确定有多少前导位用于网络标识,其余部分则用于主机/接口标识。考虑到是128位,产生的组合有很多。 Python的ipaddress模块和IPv4地址 ipaddress模块是按照CIDR表示法设计的,由于其简洁易用,受到人们的推荐。 ipaddress模块还包含了一些方法,用于在必要的情况下还原子网掩码。 IPv4地址的最初定义中包含一个“类”,这个“类”由第一个八位组中的地址范围所定义。 ipaddress模块不识别IPv4类,故在本教程中不会涉及。 ipaddress模块包含三个特定的IPv4地址对象类型: 一个“主机”,或一个不包含CIDR表示法的独立的地址对象 […]

[翻译作品]pip10 已正式发布

原文地址:https://blog.python.org/2018/04/pip-10-has-been-released.html 作者:Paul Moore 译者:首席IT民工 我代表Python包管理局(Python Packaging Authority),很高兴在此宣布:pip10刚刚正式发布了。这个版本是几个月以来社区工作的结晶。 要安装pip 10,请运行: python -m pip install –upgrade pip 或者,按照https://pip.pypa.io/en/latest/installing 所述,使用 get-pip.  如果你使用的pip版本来自于分发供应商,会由供应商在适当的时候提供升级(你也可以选择在虚拟环境中使用pip 10)。 (在Windows上使用 get-pip 有个小问题:在下载get-pip.py文件时,请重命名这个文件,以确保文件名中不包含”pip”,比如 gp.py。否则会触发pip的检查,导致运行中断。我们正在跟进这个问题,地址是:https://github.com/pypa/pip/issues/5219 )。 新版本pip 10的亮点: 已不再支持 Python 2.6 。 如果你需要在Python 2.6 上使用pip,请留在pip 9这个版本,这是支持Python 2.6的最后一个版本 支持PEP 518,允许项目指定从源代码打包所依赖的安装包。(当前对PEP 518的支持比较有限,未来的版本会提供所有的支持 – 详情请参见文档) 对于Windows上非ASCII语言环境下的Unicode字符处理,提供了显著改进 提供了新的”pip config”命令 默认的升级策略已改为:只在需要的情况下 修复了许多bug,以及多个细微改进 此外,先前宣布的pip内核重组已经开始了。除非你写的代码有导入pip模块(或者你使用了这样的代码),否则这一变化不会对你产生任何影响。如果你受到了影响,请将问题报告给问题代码的作者(推荐他们访问https://mail.python.org/pipermail/distutils-sig/2017-October/031642.html  详情请参阅公告) 感谢为新版本付出辛劳的每个人。社区成员做了许多的贡献 – 有代码方面的,有参与设计讨论的,或者上报bug的。pip开发团队由衷地感谢社区各位所做的贡献。 谢谢 Paul

[翻译作品]详解Python中的下划线

本文介绍了Python中单下划线和双下划线(”dunder”)的各种含义和命名约定,名称修饰(name mangling)的工作原理,以及它如何影响你自己的Python类。 单下划线和双下划线在Python变量和方法名称中都各有其含义。有一些含义仅仅是依照约定,被视作是对程序员的提示 – 而有一些含义是由Python解释器严格实现。 如果你想知道“Python变量和方法名称中单下划线和双下划线的含义是什么?”,我会尽我所能在这里为你解答。 在本文中,我将讨论以下五种下划线规范和命名约定以及它们如何影响Python程序的行为: 单前导下划线:_var 单末尾下划线:var_ 双前导下划线:__var 双前导和末尾下划线:__var__ 单下划线:_ 在文章结尾处,你可以找到一个简短的“速查表”,总结了五种不同的下划线命名约定及其含义。 让我们马上开始! 1. 单前导下划线 _var 当涉及到变量和方法名称时,单个下划线前缀只有约定本身的含义。 这是对程序员的一个提示 – 意味着Python社区一致认为它应该是什么意思,但程序的行为不受影响。 下划线前缀的含义是向其他程序员表示:以单个下划线开头的变量或方法仅供内部使用。 该约定在PEP 8中有定义。 这不是Python强制规定的。 Python不像Java那样在“私有”和“公共”变量之间有很强的区别。 这就像有人提出了一个小小的下划线警告标志,说: “嘿,这不是真的要成为类的公共接口的一部分。不去管它就好。“ 看看下面的例子: 如果你实例化此类并尝试访问在__init__构造函数中定义的foo和_bar属性,会发生什么情况? 让我们来看看: 你会看到_bar中的单个下划线并没有阻止我们“进入”类并访问该变量的值。 这是因为Python中的单个下划线前缀仅仅是一个约定 – 至少在涉及变量和方法名的时候。 但是,前导下划线的确会影响从模块中导入名称的方式。 假设你在一个名为my_module的模块中有以下代码: 现在,如果使用通配符导入从模块中导入所有名称,则Python不会导入带有前导下划线的名称(除非模块定义了覆盖此行为的__all__列表): 顺便说一下,应该避免通配符导入,因为它们使名称空间中存在哪些名称不清楚。 为了清楚起见,坚持常规导入更好。 与通配符导入不同,常规导入不受前导单个下划线命名约定的影响: 我知道这一点可能有点令人困惑。 如果您遵循PEP 8推荐,避免通配符导入,那么您真正需要记住的只有这个: 单个下划线是一个Python命名约定,表示这个名称是供内部使用的。 它通常不由Python解释器强制执行,仅仅作为对程序员的提示。 2. 单末尾下划线 var_ 有时候,一个变量的最合适的名称已经被一个关键字所采用。 因此像class或def这样的名称不能用作Python中的变量名称。 在这种情况下,您可以附加一个下划线来解决命名冲突: 总之,单个末尾下划线(后缀)是一个约定,用来避免与Python关键字产生命名冲突。 PEP 8解释了这个约定。 […]

Mark Minasi

也不知道还有多少人记得这本书。十多年前,靠着这本书我才算正式进入了IT业。那时候微软如日中天,拥趸众多,这本书十分畅销。 注意,这本书有1063页!有可能是我这辈子到目前为止读过的最厚的书了。。。尽管厚,这本书着实经典,易懂,让我一个不爱读书的门外汉和MSFT结下了不解之缘。 本来已经忘记了,最近在Pluralsight上听课,无意间碰到Mark Minasi的课,觉得这个名字好熟悉呀,仔细一查,原来正是此书的作者! 当年上网不便,原来Mark是这个样子滴。 我发现叫Mark的牛人确实不少。 尘封的记忆啊。

[翻译作品]2018年3月Python十大开源项目

原文地址: https://ogmcsrgk5.qnssl.com/vcdn/1/%E4%BC%98%E8%B4%A8%E6%96%87%E7%AB%A0%E9%95%BF%E5%9B%BE/python-top-10-open-source-projects-v-mar-2018-e2ce1d645ec.png 译者:首席IT民工 在过去的一个月中,我们对近250个Python开源项目进行了排名,选出了前十。 我们比较了在此期间有新的发布或是重大发布的项目。Mybridge AI基于多种因素对项目进行排名,以衡量其在专业人员眼中的质量。 本期平均点赞数:570 追踪Python前十位开源项目,并每月收到一次电子邮件 选题:日期时间,调试器,地图,数据校验,打印,交易机器人,多重比较,矩阵,下载程序 开源项目对程序员大有裨益。希望你找到一个有意思的项目,让你有所启发。 第1名 Delorean:时间旅行变得容易了[v 1.0] [Github上点赞数:1335个] 第2名 Birdseye: 快速、方便、以表达为中心的、使用AST的Python图形化调试器 [Github上点赞数:674个] 第3名 Som-tsp: 使用自组织地图技术解决旅行中的销售员所遇到的问题 [Github上点赞数:432个] 第4名 Voluptuous:尽管名字有点妖娆,这是一个Python的数据校验库  [Github上点赞数:1066个] 第5名 Icecream(冰淇淋):甜甜的,奶油般柔滑的打印调试 [Github上点赞数:530个] 第6名 Binance-trader 币安网交易者 (Binance: 区块链资产交易平台): 币安网加密货币交易机器人 (实验性的)  [Github上点赞数:590个] 第7名 Multidiff: 针对于多个对象或者数据流的二进制(数据)比较工具 [Github上点赞数:188个] 第8名 Unimatrix: 可以模拟电影《黑客帝国》中终端显示的Python脚本。默认使用半角片假名的Unicode字符,但可以使用自定义的字符集 [Github上点赞数:558个] 第9名 Mypy-protobuf (协议缓冲区):用于从协议缓冲区中生成mypy 根的开源工具  [Github上点赞数:33个] 第10名 Lulu: You-get的一个友好分叉(fork), 即爬取网络的无声下载程序  [Github上点赞数:296个] 这些就是每月开源项目的介绍。如果你喜欢这种方式,请按照您的编程技巧阅读我们网站上的每日最佳文章。

[翻译作品]我用4年时间解决了Python GIL的一个bug…

原文地址:https://vstinner.github.io/python37-gil-change.html?utm_source=mybridge&utm_medium=web&utm_campaign=read_more 作者:Victor Stinner 译者:首席IT民工 作为Python最关键的组成部分之一:GIL(全局解释器锁),我花了4年时间修复了其中的一个令人讨厌的bug。为了修复这个bug,我不得不深挖Git的历史,才找出26年前Guido van Rossum (龟叔,Python创立者) 所做的一处更改。那个时候,线程还是很深奥的东西。 我的故事是这样的。 由C线程和GIL引发的致命错误 2014年3月,Steve Dower报告了bug bpo-20891。这个bug发生在“C线程”使用Python C API时: 在Python 3.4rc3版本中,从一个非Python创建的线程中调用PyGILState_Ensure(),并且完全没有调用 PyEval_InitThreads()的情况下,将产生一个致命的退出: 发生致命的Python错误:take_gil:NULL tstate 我的第一个评论是: 以我之愚见,这是PyEval_InitThreads()中的一个Bug。 修复PyGILState_Ensure() 2年的时间里,我完全不记得这个bug了。 2016年3月,我修改了Steve的测试程序,使其与Linux兼容(该测试是为Windows编写的)。 我成功地重现了我电脑上的错误,并且为PyGILState_Ensure()写了一个修复程序。 一年后,2017年11月,卡辛斯基问道: 此修复发布了吗? 我在更新日志中找不到… 哎呀,我又完全忘记了这个问题! 这一次,我不仅安装了我的PyGILState_Ensure()修复,还编写了单元测试test_embed.test_bpo20891(): 好的,这个bug现在已经在Python 2.7, 3.6 和master(将来的3.7)中得到解决。 在3.6和master版本中,此修复带有单元测试。 我的主分支的修复,提交b4d1e1f7: 于是我关闭了问题bpo-20891 … macOS上测试发生随机崩溃 一切都很好……但一周后,我注意到我新增加的单元测试在macOS buildbots上发生了随机崩溃。 我成功地手动重现了这个bug,第三次运行时崩溃的例子: macOS上的test_embed.test_bpo20891()在PyGILState_Ensure() 中显示有竞态条件(race condition):GIL锁本身的创建…没有被加锁保护! 添加一个新的锁来检查Python是否有GIL锁,好像没有意义… 我提出了PyThread_start_new_thread()的一个不完整的修复: 我发现有一个修复是管用的:在PyThread_start_new_thread()中调用PyEval_InitThreads()。 那么,一旦生成第二个线程就会创建GIL锁。 当两个线程正在运行时,GIL不能再创建。 至少,用python代码不可以建。 如果一个线程不是由Python产生的话,此修复不能解决这个问题,但是这个线程调用了PyGILState_Ensure()。 为什么不始终创建GIL? […]