Feb 17, 2019
周末花些时间把 Rust 生命周期又翻了一遍,终于能写出一个可以编译通过的程序了😁。Rust 虽然学习曲线比较陡峭,但是掌握之后就发现这么设计确实是有道理的,尤其是对于编写正确的 C++ 程序也很有帮助。
可变与不可变
Rust 中使用 let 来绑定一个变量,默认是不可变的。也就是说默认就相当于 C++ 中 const 变量。但是实际上 C++ 中的 const 也只是只读而已。
如果想要更改一个变量的值,在声明的时候,应该加上 mut(每次写 let mut 的时候,我心里都是读作“让TM的”)
copy 和 move …
Nov 13, 2018
Python 中可以使用 os.environ 操作环境变量,前几天看到了其他几个函数 os.getenv 和 os.putenv。然而 os.putenv 是一个大坑,os.putenv 之后,在后面的 os.getenv 中并不能读出来。囧
参考
- https://mail.python.org/pipermail/python-list/2013-June/650294.html
Nov 12, 2018
如果需要记录 Core Dump 的原因,首先需要使用 faulthandler 参数启动 Python
python -X faulthandler main.py
出 core 之后,可以使用 gdb 调试
参考
- https://stackoverflow.com/questions/2663841/python-tracing-a-segmentation-fault/2664232#2664232
Oct 15, 2018
在 Linux 中, 当子进程退出的时候, 父进程可以收到信号, 但是当父进程退出的时候, 子进程并不会受到信号. 这样就造成了在父进程崩溃的时候, 子进程并不能同时退出, 而是一直会在后台运行, 比如下面的例子:
import os
import time
def loop_print():
import time
while True:
print('child alive, %s' % time.time())
time.sleep(1)
try:
pid = os.fork()
except OSError:
pass
if pid != 0: # parent
print('parent sleep for 2')
time.sleep(2)
print …
Oct 15, 2018
最近要写一个库往 influxdb 中打点, 因为要被很多程序使用, 而又要创建新的进程, 为了避免引起使用方的异常, 简单深入了解了下 Python 的并发控制, 这才发现标准库真是坑. 之前没过多考虑过, 只是凭感觉在 CPU 密集的时候使用 multiprocessing, 而默认使用 threading, 其实两个还是有很多不一样的, 除了都是并发执行以外还有很大的不同. Python 中试图用 threading 和 multiprocessing 实现类似的接口来统一两方面, 结果导致更混乱了. 本文探讨几个坑.
在多线程环境中 fork
首先不谈 Python, 我们思考一下, 在多线程环境下如果执行 fork 会怎样? 在新的进程中, 会不会所有线程都在运行? 答案是否定的, 在 fork 之后, 只有执行 fork 的线程在运行, 而其他线程都不会运行. 这是 POSIX 标准规定的:
A process …
Oct 13, 2018
aiohttp 是 Python 异步编程最常用的一个 web 请求库了, 依托于 asyncio, 性能非常吓人. 下面列举几个常见的用法:
最基础: 并发下载网页
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
'http://python.org',
'https://google.com',
'http://yifei.me'
]
tasks = []
async with aiohttp.ClientSession …
Sep 27, 2018
有时候,requests 返回的 cookies 会为空,原因是链接发生了 301/302 跳转,而 cookies 是跟着第一个响应返回的,第二个响应没有返回 Set-Cookie header。所以直接读取 r.cookies 是空的,而在 session.cookies 中是有数据的。
解决方法是直接读 s.cookies。
s = requests.Session()
r = s.get('http://httpbin.org/cookies/set?foo=bar')
cookies = requests.utils.dict_from_cookiejar(s.cookies)
s.cookies.clear()
不过需要注意的是如果在多线程环境中使用 session …
Jul 19, 2018
引用计数(reference counting)
CPython 中默认使用的垃圾回收算法是 Reference Counting。也就是对每个元素标记有多少个其他元素引用了它,当引用数降到零的时候就删除。
- 当对象增加一个引用,比如赋值给变量,属性或者传入一个方法,引用计数执行加1运算。
- 当对象减少一个引用,比如变量离开作用域,属性被赋值为另一个对象引用,属性所在的对象被回收或者之前传入参数的方法返回,引用计数执行减1操作。
- 当引用计数变为0,代表该对象不被引用,可以标记成垃圾进行回收。
为了解决循环引用的问题,CPython 使用了 Cyclic GC,遍历所有的环,并且把每一个元素的引用减一,来检测每一个引用环是不是循环应用。
标记删除(Mark and Sweep)
- 从某一个已知的还活着的对象开始,便利对象,如果经过了某个对象就认为是活着的
- 如果没有被标记的就删除
避免了循环引用的问题
实际的处理过程
Pluggable
Generational
Incremental
参考资料:
- https://www.youtube.com/watch?v=iHVs_HkjdmI …
Jul 18, 2018
昨天写了一个服务,在本地运行很好,使用 Ctrl-C 结束运行之后会清理资源,然后取消注册,然而放到 Docker 中跑之后发现结束之后资源没有释放。查了查发现原来是下面是几个因素造成的:
- Ctrl-C 发送的是 SIGINT 信号,Python 会转化成 KeyboardInterrupt 异常,而我的资源是在 finally 释放资源,所以使用 Ctrl-C 可以优雅地退出
- Python 中对其他的信号(比如 SIGTERM、SIGHUP)都不会处理,而是直接退出
- Docker 在推出的时候默认发送的是 SIGTERM 信号
所以在 docker stop 的时候服务并不能优雅的推出。
解决方法
使用 atexit 模块是不可以的,atexit 不会处理 SIGTERM。需要使用 signal 模块来,在网上找到了一份源码 …
Jul 15, 2018
文件 IO
io.Reader
和 io.Writer
。这两个是两个特别重要的 interface。一般来说凡是可以抽象为输入的 IO 操作都会使用 io.Reader。凡是可以抽象为输出的 IO 操作都会使用 io.Writer。
io/ioutil
对于配置文件等等比较小的常规文件,一般来说我们可以使用 io/ioutil 包中的辅助函数操作就好了,比较快捷方便。
函数签名 |
说明 |
func NopCloser(r io.Reader) io.ReadCloser |
把 io.Reader 包装成一个 io.ReadWriter |
func ReadAll(r io.Reader) ([]byte, error) |
读取所有字符 … |