加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 电商 > 正文

盘点Python 里关于线程安全的那些事儿

发布时间:2021-06-29 01:24:20 所属栏目:电商 来源:互联网
导读:1. 线程不安全是怎样的? 要搞清楚什么是线程安全,就要先了解线程不安全是什么样的。 比如下面这段代码,开启两个线程,对全局变量 number 各自增 10万次,每次

1. 线程不安全是怎样的?

要搞清楚什么是线程安全,就要先了解线程不安全是什么样的。

比如下面这段代码,开启两个线程,对全局变量 number 各自增 10万次,每次增量 1。

from threading import Thread, Lock 

 

number = 0 

 

def target(): 

    global number 

    for _ in range(1000000): 

        number += 1 

 

thread_01 = Thread(targettarget=target) 

thread_02 = Thread(targettarget=target) 

thread_01.start() 

thread_02.start() 

 

thread_01.join() 

thread_02.join() 

 

print(number) 

正常我们的预期输出结果,一个线程自增100万,两个线程就自增 200 万嘛,输出肯定为 2000000 。

可事实却并不是你想的那样,不管你运行多少次,每次输出的结果都会不一样,而这些输出结果都有一个特点是,都小于 200 万。

以下是执行三次的结果

1459782 

1379891 

1432921 

这种现象就是线程不安全,究其根因,其实是我们的操作 number += 1 ,不是原子操作,才会导致的线程不安全。

2. 什么是原子操作?

原子操作(atomic operation),指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会切换到其他线程。

它有点类似数据库中的 事务。

在 Python 的官方文档上,列出了一些常见原子操作

L.append(x) 

L1.extend(L2) 

x = L[i] 

x = L.pop() 

L1[i:j] = L2 

L.sort() 

x = y 

x.field = y 

D[x] = y 

D1.update(D2) 

D.keys() 

而下面这些就不是原子操作

ii = i+1 

L.append(L[-1]) 

L[i] = L[j] 

D[x] = D[x] + 1 

像上面的我使用自增操作 number += 1,其实等价于 number = number + 1,可以看到这种可以拆分成多个步骤(先读取相加再赋值),并不属于原子操作。

这样就导致多个线程同时读取时,有可能读取到同一个 number 值,读取两次,却只加了一次,最终导致自增的次数小于预期。

当我们还是无法确定我们的代码是否具有原子性的时候,可以尝试通过 dis 模块里的 dis 函数来查看

盘点Python 里关于线程安全的那些事儿

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读