线程安全
线程安全
线程不安全
即使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
线程安全
一般我们对多线程中的全局变量都会加锁处理,这种变量是共享变量,每个线程都可以读写变量,为了保持同步我们会做枷锁处理。
但是有些变量初始化以后,我们只想让他们在每个线程中一直存在,相当于一个线程内的共享变量,线程之间又是隔离的。 python threading模块中就提供了这么一个类,叫做local。local是一个小写字母开头的类,用于管理 thread-local(线程局部的)数据。对于同一个local,线程无法访问其他线程设置的属性;线程设置的属性不会被其他线程设置的同名属性替换。
threading.local,每一个线程过来,把用到了每一份资源copy给自己一份。 每个线程之间资源独立,不会产生覆盖。TLS机制 (Thread Local Storage)线程局部存储
Threading.local 应用
Flask 上下文机制就是使用的 Threading.local
线程进来 开辟一个空间给这个线程,线程操作的所有任务,都会复制一份儿到空间中
推荐阅读:
简单介绍 详解threading模块:local类的使用(六)
TLS 机制 深入理解Python的TLS机制和Threading.local()
Flask 请求上下文
详见 Flask 上下文