线程安全

线程安全

线程不安全

即使Python(CPython)拥有GIL,但是多线程环境下仍是线程不安全的。原因是某一线程不是所有步骤都是原子性。当然我们可以加锁实现 “人为原子性”。

GIL 的作用是:对于一个解释器,只能有一个thread在执行bytecode。所以每时每刻只有一条bytecode在被执行一个thread。GIL保证了bytecode 这层面上是thread safe的。

但是如果你有个操作比如 x += 1,这个操作需要多个bytecodes操作,在执行这个操作的多条bytecodes期间的时候可能中途就换thread了,这样就出现了data races的情况了。

bytecode 是CPython解释器的字节码,可以理解为ASM中的机器码

比如这小家伙就有很多条bytecodes:

>>> dis.dis(lambda x: x+1)
1           0 LOAD_FAST                0 (x)
    3 LOAD_CONST               1 (1)
    6 BINARY_ADD
    7 RETURN_VALUE

参考:multithreading

线程安全

一般我们对多线程中的全局变量都会加锁处理,这种变量是共享变量,每个线程都可以读写变量,为了保持同步我们会做枷锁处理。

但是有些变量初始化以后,我们只想让他们在每个线程中一直存在,相当于一个线程内的共享变量,线程之间又是隔离的。 python threading模块中就提供了这么一个类,叫做local。local是一个小写字母开头的类,用于管理 thread-local(线程局部的)数据。对于同一个local,线程无法访问其他线程设置的属性;线程设置的属性不会被其他线程设置的同名属性替换。

threading.local,每一个线程过来,把用到了每一份资源copy给自己一份。 每个线程之间资源独立,不会产生覆盖。TLS机制 (Thread Local Storage)线程局部存储

Threading.local 应用

Flask 上下文机制就是使用的 Threading.local

线程进来 开辟一个空间给这个线程,线程操作的所有任务,都会复制一份儿到空间中

推荐阅读:

简单介绍 详解threading模块:local类的使用(六)

源码分析 threading.local()源码分析

TLS 机制 深入理解Python的TLS机制和Threading.local()

Flask 请求上下文

详见 Flask 上下文

posted @ 2019-08-10 00:47  写bug的日子  阅读(109)  评论(0编辑  收藏  举报