Dennis Blog

Welcome to Dennis's Grocery!!!
- Sharing techs 🌟 
- Sharing recipes 🌟
- Sharing happy times 🌟

Timeouts and Cancellations for Humans

说明: 原文出处Timeouts and cancellation for humans — njs blog (vorpus.org)。 译者以已经获得了原作者的允许以翻译该文章。 本文原作者为Nathaniel J. Smith,Trio库的作者,NumPy, PyPa相关项目的代码贡献者。 术语翻译说明:翻译内容可能混用,函数参数名会保留英文,常见词(如bug)不翻译。 primitive: 原语、底层函数 cancel scope: 取消域 cancel token: 取消令牌 timeout: 超时 deadline: 大家很习惯且考虑到翻译成截止时间比较啰嗦就不做翻译了。 shield: 没有想好如何翻译,就没有做翻译。 nursery: Trio中的一个启动子任务的系统,翻译成托儿所有点傻,就未做翻译。 其他翻译:见翻译说明 本文评论使用的是disqus 引言 你的代码可能完美无缺,但不幸的是外面的世界并不这么靠谱。有些时候,其他人的代码可能会崩溃或者卡住。网络会掉线,打印机会报错。你的代码也需要为这些情况做好准备。每当你从网络读取数据、尝试获取跨进程锁、或者发送一条HTTP请求,你至少要考虑到以下三种可能: 请求可能成功 请求可能失败 请求可能挂起。春去秋来,没有成功,没有失败,没有任何响应。 前面两种情况非常直观。最后一种情况你需要使用超时来处理。几乎每一处你与其他进程、系统通信的地方都需要设置超时,如果你没有设置超时,那就是一个潜在的bug。 说实话,如果你也像大多数开发者一样,那么你的代码可能会有很多因为缺失超时导致的bug,我的代码也是这样的。因为正确进行I/O操作非常常见且重要,你可能觉得任何一种编程环境都能为所有操作提供简单而健壮的设置超时的方法。但奇怪的是,事实并不如此。大多数带超时的API都非常单调且容易出错,以至于要求开发人员把这些弄对是不切实际的。所以别难过,你的代码有这些超时相关的bug并不是你的错,而是那些I/O库的错! 我目前正在写一个I/O库。和其他任何I/O库都不一样,这个I/O库的所有卖点是它痴迷于简单易用。我想让你能够在使用Trio时,能够简单而又正确地对任意I/O操作应用超时。但是,用户友好的超时API是一件很棘手的事。所以我会在这篇博客中深入讨论各种可能的设计,特别是那些给我提供灵感的设计。接下来我会介绍我想到的设计,以及为什么我会认为该设计是古老的”状态艺术”的一个切实优化。最后,我将会讨论为什么Trio库的思路为适应面更广,同时我将会给出一个不错的同步Python的原型实现。 那么超时处理有什么难的呢? 目录: 简单的超时机制不支持抽象 绝对的deadline是可组合的(但是用起来很麻烦) 取消令牌(Cancel tokens) 取消令牌封装了取消状态 取消令牌属于水平触发,可以根据你程序的需要来确定范围 实际上因为人类的懒惰取消令牌并不可靠 取消域: Trio关于超时和取消的人性化方案 取消域(Cancel scope)是如何工作的 我们需要在哪些地方检查取消? 一个逃逸口(escape hatch) 取消域与并发 小结 还有哪些地方可以从取消域中受益? 同步、单线程Python asyncio 其他语言 现在去修复你的超时bug! 注释 翻译说明 简单的超时机制不支持抽象 最简单的处理超时的方式无疑是给每个可能阻塞的函数加上timeout参数。在Python标准库中,你可以找到像threading....

February 7, 2023 · Author Nathaniel J. Smith, translated by Dennis

Max Factory POP UP PARADE 为美好的世界献上祝福!红传说 慧慧 开箱

开箱 预订的慧慧到家了,做一个简单的开箱。 盒照 盒子就是简单的透明包装,包装中规中矩,比不了上千的手办盒子。 正脸 这只慧慧的脸我特别喜欢。脸非常正,表情也挺到位。 全身像 全身像对焦没对好,将就看一下。 装备法杖和魔法帽的大魔导师^_^ 细节 作为一款景品手办,细节会和比较贵的手办有一定的差距。比如这里头和手臂的接缝,在比较贵的手办上应该是看不到的。另外手臂上还有少许的溢色。 最后一张 摆在音响上刚刚好。 总结 这只慧慧是我买的第一个景品手办,花了185大洋从B战购入。放在柜子里和桌子上还是非常好看的。就是细节上稍微有点欠打磨,但是考虑到185的价格,当然是选择原谅。不细细端倪的话其实也不太会注意到手臂上的接缝和溢色。戴上帽子当然也不会有头上的接缝。总体来说我觉得还是很值这个价的,性价比不错。

August 17, 2022 · Dennis Xie

使用Cython实现Python Bindings

背景 语言交互接口(FFI) 一般操作系统会提供系统调用的C API。这种说法其实并不正确,但是我们假设这个说法是正确的。毕竟很多Linux发行版都是自带了GCC编译器的,我们就简单的认为提供了系统调用的C API。然后我们思考一下这么一个问题,一个非C语言是怎么实现和操作系统交互的?主要有两种方式实现,一种是使用中断来实现系统调用,另外一种方式是间接使用C语言的系统调用API。 间接调用C语言的API涉及到了语言交互接口(FFI, Foreign Function Interface)的概念。不少编程语言就通过使用FFI来实现系统调用。很多语言把FFI叫做"Language Bindings”,比如Python Bindings。还有一些语言有自己的叫法,比如Java的JNI。通过使用FFI,像Python这些语言就可以比较简单的实现系统调用。 Python Bindings Python Bindings可以让Python代码调用C API,或者在C程序中运行Python脚本。实现Python Bindings有两种基本的方式,分别如下: 使用Python的标准库ctypes 使用CPython提供的库Python/C API 和很多基础库一样,这两个库都很底层,在业务代码中使用起来会比较复杂。我们可以用一些封装好的三方库来实现Python Bindings,比如使用Cython。 使用Cython实现Python Bindings Cython简介 Cython是一种能够方便为Python编写C扩展的编程语言,其编译器可以将Cython代码编译为C代码。Cython兼容Python的所有语法且能编译成C,故Cython可以允许开发者通过Python式的代码来手动控制GIL。Cython其语法也允许开发者方便的使用C/C++代码库。通过以下命令即可安装Cython。 1 pip install Cython Cython基础使用方法 Hello, World! 所有合法的Python语法都是合法的Cython语法,我们先写一个简单的例子保存到hello.pyx。 1 2 3 # hello.pyx def say_hello_to(name): print("Hello %s" % name) 接着写一下setup文件来编译和构建这个扩展。 1 2 3 4 5 6 7 # setup.py from setuptools import setup from Cython.Build import cythonize setup( ext_modules = cythonize("hello....

August 10, 2022 · Dennis Xie

Git访问慢问题处理方法

问题 某些时候,我们拉取Git仓库的代码会遇到一些奇奇怪怪的网络问题。这些问题包含但不限于以下一些问题: 拉取速度特别慢 一些莫名其妙的TLS问题 网络中断 处理方式 遇到以上问题可以尝试使用代理来解决。在Github上,远程仓库一般使用https协议或者ssh协议。下面分别提供两种协议的代理的配置方法。 https协议 为Git命令行添加http代理配置即可,命令如下: 1 git config --global http.proxy http://proxyUsername:proxyPassword@proxy.server.com:port 运行该命令后, ~/.gitconfig文件中会增加如下的配置: [http] proxy = http://proxyUsername:proxyPassword@proxy.server.com:port 通过该方法可以解决https协议的远程仓库访问问题。 ssh协议 使用ssh协议的仓库链接一般为 git@github.com:gituser/repository.git。这里User为git,Host为github.com。因为使用了ssh协议,配置一下ssh的代理即可。首先打开或者创建 ~/.ssh/config 文件。以Github为例,填入以下内容: Host *.github.com User git ProxyCommand nc -v -x {proxy.server.com or ip}:{port} %h %p 如果要针对其他Git仓库代理,Host需要修改成对应域名,User也需要以仓库的地址为准。这里的代理命令使用了nc命令,所以需要系统装了netcat才行。 tips: git@github.com:gituser/repository.git实际上是ssh://git@github.com/gituser/repository.git的简写 其他问题 我自己是在WSL2中配置的代理,代理服务运行在Windows中。这里就出现了WSL2访问Windows的服务的问题。在WSL2中,可以使用$(hostname).local来获取到Windows的域名。由于Windows的防火墙问题,这时实际上还是不能访问成功。有以下几种解决方案可以尝试: 增加防火墙入站规则(这个方法在我本机上还没有实验通过) 配置公用配置文件的受保护的网络连接 取消掉图中WSL的网络连接。这个方法需要每次重启后配置一次,因为WSL这个网络需要WSL启动后才会出现。 配置允许通过防火墙的应用 控制面板->系统和安全->Windows Defender 防火墙->允许的应用,把需要访问的服务的公有网络打开即可。如果你在用IDEA调试程序,那么你需要把Java的公有网络打开才能在WSL2里访问这个在调试的服务。 关闭公用网络防火墙 引用 Configure Git to use a proxy git 设置和取消代理

August 9, 2022 · Dennis Xie

Docker多阶段构建

问题背景 如果有这么个情况,因为某些原因需要合并多个docker镜像里面的文件来组成一个单一的镜像,应该怎么办? 解决方案 使用Docker的多阶段构建。 多阶段构建 多阶段构建解决的问题 通常来说服务构建、测试和部署一般会使用不同的镜像。其中不同的镜像会有一些不同的工具,如构建镜像会包含一些基础构建工具。测试镜像会包含一些分析测试结果的工具。部署镜像则是最精简的镜像,仅包含正常运行所需要的工具和环境等。 在没有多阶段构建的情况下,我们可能会一个脚本来完成程序构建、测试镜像的生成和部署镜像的生成等工作。如下面的代码所示: 1 2 3 4 5 docker build -t demo:build -f Dockerfile.build . docker container create --name demo demo:build docker container cp demo:/path/to/build/app ./app docker container rm -f demo docker build -t demo:deploy-latest -f Dockerfile . # copy the app into the deploy image 这样可以保证不同用途的镜像的精简程度,尤其是避免生产环境使用的镜像太肥。有了多阶段构建以后,我们就可以把这些操作移动到Docker镜像构建中去。 使用方法 多阶段构建可以将Docker镜像的构建划分成多个不同阶段,不同阶段使用不同的基础镜像,后面的构建阶段可以使用前面阶段的一些结果。示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 FROMbase0 # stage without nameRUN build somethingFROMbase1 AS stage1 # stage with a nameRUN build other thingsFROMrunningiamge:latestWORKDIR/running/pathCOPY --from=0 /base0/build/app ....

June 21, 2022 · Dennis Xie

Spring Web程序中Servlet, Filter及Bean的管理

1 背景 1.1 问题 最近接触到两个问题。问题本身并不难,但是我自己因为对Servlet和Spring不够熟没有回答正确。问题如下: Spring Web程序中, Filter对象能不能使用Spring容器中的Bean? Spring Web程序中, 能不能给Service Bean注入Controller Bean? 1.2 问题拆解 这个问题需要分情况 通过Spring Boot加载的Spring Web程序 通过Servlet容器加载的Spring Web程序取决于是否有做Context继承 2 分析 备注: 本文基于Servlet 3.0及Spring Web MVC 5.3.x分析 2.1 通过Servlet容器加载Servlet 2.1.1 Servlet 3.0加载Servlet的方式 Servlet 3.0开始支持通过SPI加载Servlet的方案 Spring通过 org.springframework.web.SpringServletContainerInitializer 实现了Servlet 3.0中的 ServletContainerInitializer 接口。 SpringServletContainerInitializer 则会在初始化的时候去加载所有的实现了 org.springframework.web.WebApplicationInitializer 的类。 用户通过实现该类即可创建和加载Servlet对象。 2.1.2 创建单Spring容器的Servlet 官方代码示例如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) { // Load Spring web application configuration AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context....

June 8, 2022