[翻译作品]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个]

image.png

第2名

Birdseye: 快速、方便、以表达为中心的、使用AST的Python图形化调试器 [Github上点赞数:674个]

image.png

第3名

Som-tsp: 使用自组织地图技术解决旅行中的销售员所遇到的问题 [Github上点赞数:432个]

image.png

第4名

Voluptuous:尽管名字有点妖娆,这是一个Python的数据校验库  [Github上点赞数:1066个]

image.png

第5名

Icecream(冰淇淋):甜甜的,奶油般柔滑的打印调试 [Github上点赞数:530个]

image.png

第6名

Binance-trader 币安网交易者 (Binance: 区块链资产交易平台): 币安网加密货币交易机器人 (实验性的)  [Github上点赞数:590个]

image.png

第7名

Multidiff: 针对于多个对象或者数据流的二进制(数据)比较工具 [Github上点赞数:188个]

image.png

第8名

Unimatrix: 可以模拟电影《黑客帝国》中终端显示的Python脚本。默认使用半角片假名的Unicode字符,但可以使用自定义的字符集 [Github上点赞数:558个]

image.png

第9名

Mypy-protobuf (协议缓冲区):用于从协议缓冲区中生成mypy 根的开源工具  [Github上点赞数:33个]

image.png

第10名

Lulu: You-get的一个友好分叉(fork), 即爬取网络的无声下载程序  [Github上点赞数:296个]

image.png

这些就是每月开源项目的介绍。如果你喜欢这种方式,请按照您的编程技巧阅读我们网站上的每日最佳文章。

[翻译作品]我用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:

image.png

于是我关闭了问题bpo-20891 …

macOS上测试发生随机崩溃

一切都很好……但一周后,我注意到我新增加的单元测试在macOS buildbots上发生了随机崩溃。 我成功地手动重现了这个bug,第三次运行时崩溃的例子:

image.png

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?

Antoine Pitrou问了一个简单的问题:

为什么不在解释器初始化时总是调用PyEval_InitThreads()? 有什么缺点吗?

感谢git blame和git log,我发现了“按需”创建GIL的代码,来自于26年前做出的改变!

image.png

我的猜测是,动态创建GIL的目的是为了减少GIL的“开销”。这些GIL用于那些只使用单个Python线程的应用程序(永远不会产生新的Python线程)。

幸运的是,Guido van Rossum在我附近,能够对基本原理加以阐述:

是的,最初的理由是线程是深奥的,不为大多数代码所使用,并且当时我们一定觉得:总是使用GIL会导致(微小的)速度放缓,并增加由于GIL代码中的错误而导致崩溃的风险。 我很高兴得知我们不再需要担心这一点,并且可以始终对其进行初始化。

提出Py_Initialize()的第二个修复

我提出了Py_Initialize()的第二个修复,以便在Python启动时始终创建GIL,并且不再“按需”,以防止出现竞态条件的风险:

image.png

Nick Coghlan问我是否可以通过性能基准测试我的补丁。 我在我的PR 4700上运行pyperformance。差异至少5%:

image.png

哦,5个基准比较慢。 Python中性能退步是不受欢迎的:我们正在努力让Python变得更快!

在圣诞节前忽略错误测试

我没有想到5个基准测试会变慢。 我需要进一步的调查,但时间不够。也许是我太害羞,或者羞于承担导致性能退步的责任。

在圣诞节假期之前,我没有做任何决定,而test_embed.test_bpo20891()在macOS buildbots上仍然是随机失败。 在离开两个星期之前,我对于触及Python的关键部分,即GIL,并没有太多把握。 所以我决定,等到我回来之前,先跳过test_bpo20891()。

没有圣诞礼物给你了:Python 3.7。

运行新的基准测试,和应用于master的第二个修复

在2018年1月底,我再次运行了那5个由于我的PR(Pull request)而变慢的基准测试。 我使用了CPU隔离,在我的笔记本电脑上手动运行这些基准测试:

image.png

好吧,它证实了,依照Python性能基准套件,我的第二个修复对性能没有显著的影响。

我决定将我的修复程序推送到master分支,提交2914bb32:

image.png

然后我在master分支上重新启用了test_embed.test_bpo20891()。

没有适用于Python 2.7和3.6的第二个修复,抱歉!

Antoine Pitrou认为,不应该合并Python 3.6的backport (注:backport是将一个软件的补丁应用到比此补丁所对应的版本更老的版本的行为):

我不这么认为。 人们可能已经调用PyEval_InitThreads()。

Guido van Rossum也不想把这一修改做backport。 所以我只从3.6的分支中删除了test_embed.test_bpo20891()。

由于相同的原因,我没有将我的第二个修复应用于Python 2.7。 而且,Python 2.7没有单元测试,因为它很难backport。

至少,Python 2.7和3.6获得了我的第一个PyGILState_Ensure()修复。

结论

在少数案例中,Python仍然存在一些竞态条件。 当一个C线程开始使用Python API时,在创建GIL时就可以发现这样的Bug。 我推出了第一个修复程序,但在macOS上发现了一个新的不同的竞态条件。

我不得不深入研究Python GIL的历史(1992年)。 幸运的是,Guido van Rossum也能够阐述其基本原理。

在基准测试出现故障后,我们同意修改Python 3.7,以便始终创建GIL,而不是按需创建GIL。 该变化对性能没有显著的影响。

我们还决定让Python 2.7和3.6保持不变,以防止任何回退风险:可以继续按需创建GIL。

我花了4年的时间修复了Python GIL中的一个令人讨厌的bug。 在接触Python中如此关键的部分时,我从未自信满满。 现在,我很高兴这个bug被我们甩在了身后:现在,它已经在未来的Python 3.7中完全修复了!

完整的故事见bpo-20891。 感谢帮助我解决这个Bug的所有开发人员!

[翻译作品]数据科学笔记本变得真实了:JupyterLab已面向用户发行

作者:Andrew Brust

原文地址:http://www.zdnet.com/article/can-data-science-notebooks-get-real-jupyter-lab-releases-to-users/

译者:首席IT民工

副标题:Jupyter 笔记本已经突破了他们“展示和讲解”的角色,正变得更适合数据工程师使用。JupyterLab 会把这些笔记本升级成一款企业级工具吗?

现如今,业内人士相信,数据和分析都可以借助人工智能的服务来完成。鉴于此,作为数据科学家看来最受欢迎的数据处理工具 — 笔记本, 相关的介绍很多。这一领域的巨头有 Apache Zeppelin,和更加著名的 Jupyter (前身是iPython)。如果你的工作平台是Databricks,通常你最后都会使用他们自有品牌的笔记本。即便如此,这些笔记本都和Jupyter兼容。

可以把笔记本看成是一个你存放代码并添加注释的地方。不过,也许更准确地说法是,笔记本是存放大量注释,并用代码加以修饰的地方。无论你想要多么尖锐,有了笔记本,你可以在Markdown格式的富文本中,穿插任意语言的代码,本地运行,然后以文本、表格或是图形的方式来查看结果。如果你足够细致的话,甚至可以把这些资产拼凑成某个穷人的仪表盘。

超越演示功能

笔记本的问题在于,相比于生产环境里的数据工程工作,它更适合实验性质的数据科学工作。虽然这只是我自己的看法,我却坚持这么认为。笔记本更多的是关于演示而非开发,而且缺少了很多IDE(集成开发环境)比如Eclipse, PyCharm, Visual Studio, RStudio的好的功能。

不过,凡事总有变化。Jupyter 笔记本起初是Python代码的专属工具,也是Anaconda的一部分。Anaconda包含了主要的Python发布,一直致力于通过JupyterLab增强Jupyter笔记本的功能,使其更像是一个IDE。本周早些时候,JupyterLab,这款受到长期吹捧的工具终于发布,可供开发者使用。考虑到这是个不大却很重要的里程碑事件,我决定下载JupyterLab,跑一跑,并看看怎么样。整体而言,我印象深刻。

image.png

JupyterLab,一个基于R语言的笔记本和它的几种可视化结果,显示在了同一个版面上

编码生产力

JupyterLab是包含了Jupyter(笔记本)的超集。所以,在Jupyter笔记本中能做的事情,在JupyterLab中都可以做。而且能做的事情更多。

首先,一些笔记本能够提供的,比如Tab键语法完成,Shift-Tab键查看对象工具的提示这些功能依然都在。比起独立的Jupyter 笔记本来说,JupyterLab的功能更强:在Tab键完成时,提供匹配条目的类型的额外信息;在工具提示中,也提供对象相关的更多信息。有了这种基于上下文的辅助功能,开发者不必老是切换上下文,以便把事情给想清楚。

开发者们也可以工作在偏命令行风格的编程模式下,即,在控制台(而不是笔记本)内交互地运行他们的代码。控制台是与Jupyter内核建立的实时会话(实际上语言解释器是在笔记本后台完成代码的执行),所以,开发者可以先在控制台环境中运行代码,然后在以文本和图形为主的文档(显示在笔记本中)中插入这些代码。

比笔记本更强大

然而,JupyterLab远远超越了笔记本的功能。它允许开发者打开多种格式的文件,这些文件中包含了他们可能用到的,或者由代码产生的数据和其他资源。文件类型包括:支持语言的源代码文件,纯文本、CSV(和其他分隔符的文本格式)、JSON、各类图片、甚至是PDF格式的文件。查看器和编辑器则包括:全功能的文本编辑器,图片查看器,表格数据查看器,带树形视图的JSON查看器,以及适用Vega, Vega-Lite和VDOM文件的查看器。

有时候,某些特定的文件适用于多个查看器。比如说,JSON和CSV文件都能以纯文本方式打开。不过其实,JSON也可以用树形视图查看器打开,CSV也可以用表格查看器打开。Jupyter支持用多个编辑器同时打开这样的文件,并且保持多个视图间的同步,以便在一个编辑器中所做的修改,显示在另一个编辑器中。

双重视图

多视图模型也适用于笔记本。比如,只要在笔记本内已显示的图像上单击右键,并从菜单中选择“为输出建立新视图”,多个图像就可以并排地以各自视图的方式显示出来,包括笔记本的传统视图。

一点点拖放就可以办到。支持在近似水平或垂直的区域中,显示多个笔记本、输出结果和文件查看器。区域之间用分隔列分开,每个区域容纳了多个标签文档,每个文档支持单独上下滚动。一旦你习惯于创建这种布局,你甚至能够排列出如上图所示的仪表盘风格的布局。

单文档,多语言

需要承认的是,这些养眼的东西有时候会让人分心。所以,JupyterLab支持用户在这种分块布局和单文档视图之间进行切换。在单文档视图中,活动文档会占据JupyterLab浏览器页或窗口的整个编辑区域。

JupyterLab支持Chrome,Firefox和Safari浏览器。据我有限的测试,除了单文档视图会导致严重的显示异常以外(我确认该异常在Chrome中不存在),JupyterLab在Windows 10 Edge浏览器中也运行良好。

image.png

JupyterLab启动器

类似Jupyter, JupyterLab支持多语言,前提是这些语言的内核已安装好。如上图所示,启动器允许用户选择一种语言来创建新的笔记本,或是控制台。默认已安装了Python内核。据我测试,我成功地安装了R和Node/JavaScript内核。

下图显示了一个基于Node.js的笔记本,以及其中一种显示结果的单独视图。

image.png

不需要讨厌的安装程序了,真的吗?

归功于其对多种技术的组合,JupyterLab的安装可以很复杂。首先,在你的系统上安装Anaconda Python,它会安装Jupyter的核心文件。接下来,安装R内核的支持文件。然后,你可以下载JupyterLab,分别安装其他语言和Jupyter内核。我是这么安装Node.js内核的,做了好几步才弄对。去掉范例笔记本则耗费了额外的研究时间,安装那些提供代码支持所必须的模块也是如此。

安装也许有些难度,但并不高深(不算数据科学)。我曾经做过程序员,现在依然爱倒腾各种工具,所以我对这些东西有种本能。但是,我的编码技能退化了,也不再是使用工具的好手了。如果我可以办到,那么任何有基本技能和对JupyterLab感兴趣的人也可能没什么问题。不过,耐心和空余时间还是需要的。如果有一个主要安装程序,则会减少很多麻烦。

云应用的红利

对于需要Jupyter用户来说,由于很多云服务(包括微软HDInsight,亚马逊SageMaker,及谷歌的Cloud DataLab)中已经包含了Jupyter,安装不成问题。不知道这些包含Jupyter的服务和产品中也会包含JupyterLab吗?但愿如此,因为这样做会让这些平台上的数据工程体验更好。

基于Web浏览器的开发工具富有创新性,但也有其局限性。对于这个难题,Jupyter是一个好榜样。JupyterLab有助于超越这些局限,又不失创新性和便利性。让我们希望它在生态系统中的应用越来越火。

[翻译作品]我2018年开始Django开发时踩过的坑

作者:Luan Nguyen

原文地址:https://peeomid.com/blog/2018-01-26-what-i-wish-i-knew-when-i-started-django-development-2018/

副标题:Django – 当你开始一个新项目时要注意的地方 – 2018年更新

译者:首席IT民工

现在回想起来,如果在开始Django之旅的时候我注意了这几个地方,会省去我大量的时间和精力。

延伸阅读(Too Long To Read): 注意使用cookiecutter-Django 以便上手所提到的大部分东西。

当我开始做web开发时,我是一名普通的php程序员,不屑于老是看文档。经过努力,总能从搜索引擎中找到解决方法(嗯,现在仍然如此)。

让我很不爽的是,有时候各种东西搅和在一起,你很难读懂别人的代码,甚至是几个礼拜前自己写的代码。这一点不可小觑,阅读代码总是花很多时间。

Python(以及Django)的出现解救了我。第一次,我能够轻松地阅读别人的代码了(也不全是,哈哈)。阅读,变得更简单了。事实上,通过阅读别人的代码,我的技能提高了很多。然而,和其他人一样,一开始我犯了很多,尤其是Django相关的错误。

以下是我希望记录下来的东西,对于开始时踩过的那些坑,我会逐一添加。

Cookie cutter Django

每次当我开始一个项目时,总会创建一个什么都没有的空白项目。然后,反复地修改项目,直到出现我希望的设定/结构。

我原以为我只要为新项目建一个代码库,然后继续开发就好了,但实际上维护和更新这个代码库却占用了大量的时间。

cookiecutter-Django 是一个超棒的项目。有了它,你可以在开始项目时就应用很多人称“最佳实践”的东西。它也自带了一些有助于加速开发的常用组件。

Virtualenv

如果你已经看过一些Python文档,你应该见过这个东西。再怎么推荐都不为过啊。

一定要使用virtualenv来分开每个项目的开发环境。即使你开始的时候只有一个项目,不要都放在global里面,并且你很快就有更多的项目的。

当你创建一个新的环境时,可以这样指定Python版本:

virtualenv env -p python3

另外,确保你查看一下 virtualenvwrapper,这篇文档能帮助你轻松地管理各种不同的虚拟环境:

  • 在一个地方存储所有的虚拟环境
  • 尽快进入虚拟环境,比如,只要运行workon awesome project就好了
  • 设定好当你进出这些环境时所运行的脚本(简单的例子如:切换到项目所在目录,启动一些东西)

设定之结构

这是另一件重要的事情 — 我是认真的。

常规的开发流程是这个样子:你进行本地开发,然后推送到某种测试服务器,最后上线。

每个环境都有其自身的设定和配置(比方说,本地的数据库配置会不同于生产环境的配置)。

对于特定的东西,尤其是那些敏感信息,可以选择从环境变量来获取。

其他的东西,你可以为不同的环境准备不同的设定文件,如图所示:

image.png

base.py 包含常见的环境设定;local.py 包含属于本地环境的设定

local.py, staging.py 和 production.py 会导入base.py的设定。你可以借助环境变量来决定要用哪个设定文件。

manage.py的例子:

os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘config.settings.local’)

如果你使用cookiecutter-django,这些是已经存在的!

从一开始自定义用户模型

始终从一开始就选择自定义用户模型。

你可能会觉得对于简单的项目,没必要开始的时候需要一个自定义的用户模型(我原来也这样认为)

可是呢,如果项目持续一段时候后,你很有可能很快需要转到用户模型,以便引入额外的东西。迁移到用户模型并不总是一件有乐趣的任务。

用于监控的Sentry

用Sentry来进行监控。真的,很简单很容易。你能获得些什么?

  • 当你的站点有问题时,会有通知邮件
  • 管理你的问题(给事情打勾,哈哈)
  • 问题的统计

几个可以使用的App

  • Django-extensions 包含很多东西,我并非都用过。比如:

runserver_plus: 不是常规的runserver,而是用来本地运行服务的。你会接触到很好看的调试界面,每步都提供交互式Python Shell! (这点是最吸引我的)

show_urls: 显示所有项目的urls,和他们指向的视图。

  • django-debug-toolbar 调试工具栏可以显示很多东西,比如调试消息,比如执行了那些SQL查询。
  • django_builder 你只需要引入你的模型,然后它会生成各种东西,是的,有url, 视图,表单,测试。

[翻译作品]Python + Memcached: 在分布式应用程序中实现高效缓存

作者 Julien Danjou

原文地址:https://realpython.com/blog/python/python-memcache-efficient-caching

译者:首席IT民工

在开发Python程序时,实现缓存是重要的一环。缓存技术能够在很大程度上提升性能,从而避免数据的重复计算,或是数据库访问过慢的问题。

Python内置了实现缓存的技术,包括简单的字典和诸如functools.lru_cache之类更加完整的数据结构。后者可以利用“最近最少使用”算法限制缓存的大小,做到任意缓存。

然而,依照定义,这些数据结构仅限于Python进程内部使用。这可能对大规模分布式应用导致问题,因为当你的程序的多个副本在大规模平台上运行时,使用这种本地内存中的数据结构将不允许对所缓存的内容进行共享。

image.png

因此,如果你的系统是基于分布式网络的,就需要缓存也基于分布式网络。现如今大量的网络服务器提供了缓存能力–我们在how to use Redis for caching with Django (如何使用Redis实现Django缓存)一文中已经提到过。

在这篇教程中你将看到,memcached是实现分布式缓存的一个很好的选择。首先是对基本的memcached使用方法的简介,然后你会学习到一些高级方法,比如检查和设置(cache and set),以及使用后备缓存以避免传统的缓存性能问题。

安装memcached

Memcached提供了[很多平台的版本](https://github.com/memcached/memcached/wiki/Install) :

  • 如果你运行的是Linux,安装命令是 apt-get install memcached 或 yum install memcached 你既可以通过预构造的安装包安装,也可以从源文件安装
  • 对于macOS,使用Homebrew安装是最简单的。只要有Homebrew包管理器,直接运行 brew install memcached
  • 对于Windows, 你需要自行编译memcached,或者寻找预编译的版本

安装完毕后,运行memecached命令即可启动它:

$ memcached

在正式使用memcached的功能之前,你还需要安装一个memcached的客户端库。下面介绍安装的方法,以及基本的缓存访问操作。

使用Python存储和检索缓存值

即便你从未使用过memcached,也很容易理解。基本来说,memcached提供了一个超大的网络字典。这个字典的几个属性不同于经典的Python字典:

  • 键和值都必须是bytes(字节)
  • 到了过期时间后,键和值将被自动删除

因此,与memcached交互的两个基本操作是:set和get。正如你可能猜到了,他们分别表示给某个键赋值,和从某个键取值。

我个人偏爱的与memcached交互的Python库是 pymemcache,推荐使用。它用pip就可以安装:

$ pip install pymemcache

以下代码显示了如何连接memcached和如何在你的Python程序中将它用作网络分布式缓存:

image.png

memcached网络协议十分简单,其实现运行起来也非常快,使得它在数据存储上很管用。换作其他技术,这些数据要么访问起来很慢,要么需要重新计算。

这个例子简单明了,却演示了键值的跨网络存储,以及程序的多个分布式副本如何来访问键值。很简单,却很强大。这是很棒的迈向程序优化的第一步。

缓存数据的自动过期

在memcached中存储数据时,你可以设置过期时间,即mecached保存键和值的最长时间,单位是秒。到期以后,memcached会自动从缓存中删除他们。

过期时间应该设多长呢?没有一个直接的答案,过期时间完全取决于你处理的数据和程序的类型。可能是几秒钟,也可能是几个小时。

“缓存失效”定义了当缓存中的数据与当前数据不一致时,什么时候删除缓存数据,这也是你的程序必须处理的问题,尤其是在不得不呈现已经过时或过于陈旧的数据的情况下。

重申一下,没有直接的答案;过期时间取决于你构造的程序类型。不过,有几类外围情况需要处理,我在上面的例子中尚未涉及。

缓存服务器不能无限增长–内存是有限资源。因此,服务器一旦需要更多的空间来存储其他东西,就会立即清空已有的键。

有些键由于到了过期时间(有时叫做生存周期,或TTL),会变无效。在这些情况下,数据会丢失,并且必须再次重新从标准数据源查询。

听上去比实际情况更加复杂。通常来说,你在Python中使用memcached可以遵循以下方式:

image.png

注:由于存在清理操作,处理丢失的键是一定要做的。此外,像memcached刚刚启动这种冷缓存的情况也必须进行处理。在这种情况下,缓存是全空状态,需要一次载入一个请求,直至充分填满。

这意味着说,任何缓存的数据都应视作是临时性的。而且,千万不要期望缓存中包含你先前写入的值。

冷缓存的预热

有些冷缓存的情况是无法避免的,比如memcached发生了崩溃。而有些冷缓存情况,比如迁移到一个新的memcached服务器,是可以避免的。

当你预见会发生冷缓存的情况时,最好避开它。一个需要重新填满的缓存。意味着突然之间,所有缺少缓存数据的用户会大量地访问标准数据源。这种现象也称作“惊群效应”。

pymemcache库提供了一个名为FallbackClient的类来实现这种场景,如下所述:

image.png

FallbackClient类能够依照顺序,查询传递给构造函数的老的缓存。这种情况下,总是优先查询新的缓存服务器。如果未命中,则查询老的缓存,从而避免来回查询主数据源的可能。

键会被设置到新的缓存中。一段时间后,可以淘汰老的缓存,然后用new_cache客户端直接替换FallbackClient

检查和设置

在与缓存进行远程通信时,可能发生常见的并发性问题,即有多个客户端尝试同时访问同一个键。Memcached提供了一个叫做检查和设置(check and set)的操作,缩写CAS,来解决这一问题。

最简单的例子比如,有个程序希望统计它的用户数。每当有用户连接时,计数器加一。用memcached,简单实现起来是这样子的:

image.png

然而,如果这个程序的两个实例尝试同时更新这个计数器,情况会怎样呢?

第一个client.get(‘visitors’)调用会返回相同的用户数,比方说是42。两个实例同时加一,结果是43,但是43是错的,正确的结果应该是42+1+1 = 44。

通过CAS操作解决并发问题,就很方便。以下的片段实现了一个正确的方案。

image.png

类似于get方法,gets方法既返回键值,又返回CAS值。

值的内容是无关的,但在下一次cas方法的调用中会用得着。除了值的内容自gets操作后发生了变化就会导致运行失败,这个方法等同于set操作。运行成功时,循环是中断的,否则操作会从头开始。

当程序的两个实例尝试同时更新计数器时,只有一个实例可以成功地将计数器从42加到43。另一个实例会由client.cas调用返回一个“假”值,只能再次走一遍循环。这次它会得到43,加1得到44,且cas调用会成功完成,从而解决了我们的问题

增加计数器这个例子的有趣之处在于,简单地解释了CAS的工作原理。其实,memcached其实提供了incr和decr方法,可以在单个请求中递增或递减,而无需多次调用gets / cas 。 现实中的程序中使用gets/cas来实现更加复杂的数据类型或者操作。

大多数的远程缓存服务器和数据存储都提供了类似的方法,以防止出现并发性问题。了解和合理的使用这些方法至关重要。

更多缓存知识

这篇教程演示了使用memcached来提高Python程序的性能是多么的容易。

只要执行两个基本的”set”和”get”操作,你就可以加速数据检索,或者避免反复的计算结果。有了memcache,你可以在大量的分布式节点间实现缓存的共享。

另外,类似CAS操作更高级的方法允许你跨多个Python线程/进程并发地更新缓存中的数据,同时不破坏这些数据。

如果你有兴趣学习更多的高级技巧,写出更快、扩展性更好的Python程序,可以访问Scaling Python。它包含了许多高级主题,比如网络分布,排队系统,分布式哈希算法,和代码性能分析。

I am an Escalation Engineer

What does a Microsoft Escalation Engineer do?

“If an Enterprise has a problem with it, we are the ones that are the last level, code level support. We’re the last step between the Serviceability team within Windows that would then provide hot-fixes.

One of the most rewarding things about this job is that it’s never the same thing twice.

If you have a question about Windows, there is nobody that knows more about Windows than this team collectively.

Not only are you trying to solve the problems but you also need to sort of manage your customers. If you’re talking to the CTO you might be a hostage negotiator.”

I like this jacket that I received as becoming an EE.

Long Live NT Debugging

A Brief Introduction of Outlook’s Architecture

When you are troubleshooting Outlook connectivity issues, you may be exposed to a lot of concepts, such as MAPI, RPC, etc. If you ever wonder what they are and how they fit together to make Outlook connectivity possible, you need to have a good understanding of Outlook’s architecture.

In general, there are several layers when it comes to Outlook connecting to a messaging system (like Exchange Server):

– Outlook
– MAPI Layer
– Service Provider Layer
– Transport Provider
– IP / Ethernet Layer

The interfaces between layers are COM interfaces. Each layer exposes one or more COM interfaces as well as methods on these interfaces.

For Outlook connectivity to work, each layer needs to function as expected. I made a simple graph and hope that it helps with understanding of these layers.

EMSMDB32 is a dll file you may have seen a lot if you have ever diagnosed Outlook connectivity issues.

EMSMDB is short for Electronic Messaging System Microsoft Database Provider. As its name implies, it’s a database provider. As such, it enables reading and writing messages to an Exchange store.

Since Outlook 2007, EMSMDB is also an address book provider as well as a transport provider. In other words, Outlook calls the methods provided by EMSMDB32 to access an Exchange store, to open the address book, and to submit messages to Exchange server.

Internally, the role of EMSMDB32 is to receive the calls from upper MAPI layers and convert them into ROP calls that are understood by Exchange.

The common methods provided by EMSMDB32 are EcDoConnect, EcDoDisConnect, EcDoRpcExt2, EcRRegisterPushNotification. At transport layer (RPC), each of these methods has a corresponding Operation number (OPNUM). For the details on this relationship, see MSDN article http://msdn.microsoft.com/en-us/library/ee178982(v=exchg.80).aspx

That’s some basic stuff about EMSMDB. Until next time.