Yifei Kong

Feb 17, 2019

Rust 的生命周期管理概述

周末花些时间把 Rust 生命周期又翻了一遍,终于能写出一个可以编译通过的程序了😁。Rust 虽然学习曲线比较陡峭,但是掌握之后就发现这么设计确实是有道理的,尤其是对于编写正确的 C++ 程序也很有帮助。

可变与不可变

Rust 中使用 let 来绑定一个变量,默认是不可变的。也就是说默认就相当于 C++ 中 const 变量。但是实际上 C++ 中的 const 也只是只读而已。

let x = 5;
x = 6;  // 非法

如果想要更改一个变量的值,在声明的时候,应该加上 mut(每次写 let mut 的时候,我心里都是读作“让TM的”)

let mut = 5;
x = 6

copy 和 move …

Nov 13, 2018

Nov 12, 2018

Oct 15, 2018

使用 prctl 在父进程退出的时候安全退出子进程

在 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

吐槽一下 Python 混乱的 threading 和 multiprocessing

最近要写一个库往 influxdb 中打点, 因为要被很多程序使用, 而又要创建新的进程, 为了避免引起使用方的异常, 简单深入了解了下 Python 的并发控制, 这才发现标准库真是坑. 之前没过多考虑过, 只是凭感觉在 CPU 密集的时候使用 multiprocessing, 而默认使用 threading, 其实两个还是有很多不一样的, 除了都是并发执行以外还有很大的不同. Python 中试图用 threading 和 multiprocessing 实现类似的接口来统一两方面, 结果导致更混乱了. 本文探讨几个坑.

在多线程环境中 fork

首先不谈 Python, 我们思考一下, 在多线程环境下如果执行 fork 会怎样? 在新的进程中, 会不会所有线程都在运行? 答案是否定的, 在 fork 之后, 只有执行 fork 的线程在运行, 而其他线程都不会运行. 这是 POSIX 标准规定的:

A process …

Oct 13, 2018

Python 高性能请求库 aiohttp 的基本用法

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 为空的一个坑

有时候,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

Python 中的 GC(垃圾回收)

引用计数(reference counting)

CPython 中默认使用的垃圾回收算法是 Reference Counting。也就是对每个元素标记有多少个其他元素引用了它,当引用数降到零的时候就删除。

  1. 当对象增加一个引用,比如赋值给变量,属性或者传入一个方法,引用计数执行加1运算。
  2. 当对象减少一个引用,比如变量离开作用域,属性被赋值为另一个对象引用,属性所在的对象被回收或者之前传入参数的方法返回,引用计数执行减1操作。
  3. 当引用计数变为0,代表该对象不被引用,可以标记成垃圾进行回收。

为了解决循环引用的问题,CPython 使用了 Cyclic GC,遍历所有的环,并且把每一个元素的引用减一,来检测每一个引用环是不是循环应用。

标记删除(Mark and Sweep)

  1. 从某一个已知的还活着的对象开始,便利对象,如果经过了某个对象就认为是活着的
  2. 如果没有被标记的就删除

避免了循环引用的问题

实际的处理过程

Pluggable Generational Incremental

参考资料:

  1. https://www.youtube.com/watch?v=iHVs_HkjdmI …

Jul 18, 2018

在 Python 中优雅地处理 SIGTERM 信号

昨天写了一个服务,在本地运行很好,使用 Ctrl-C 结束运行之后会清理资源,然后取消注册,然而放到 Docker 中跑之后发现结束之后资源没有释放。查了查发现原来是下面是几个因素造成的:

  1. Ctrl-C 发送的是 SIGINT 信号,Python 会转化成 KeyboardInterrupt 异常,而我的资源是在 finally 释放资源,所以使用 Ctrl-C 可以优雅地退出
  2. Python 中对其他的信号(比如 SIGTERM、SIGHUP)都不会处理,而是直接退出
  3. Docker 在推出的时候默认发送的是 SIGTERM 信号

所以在 docker stop 的时候服务并不能优雅的推出。

解决方法

使用 atexit 模块是不可以的,atexit 不会处理 SIGTERM。需要使用 signal 模块来,在网上找到了一份源码 …

Jul 15, 2018

Go语言读写文件相关函数对比

文件 IO

io.Readerio.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) 读取所有字符 …
Next → Page 1 of 8