为什么python多线程同时写一个数据会不安全

本文使用python语言讲解为什么多线程在不加锁的情况下同时修改一个变量是不安全的, 启动5个线程,每个线程都会对变量a执行100000次加1操作, 最后print(a)时,最直观的猜想,a的值是500000,然而实际情况却并不是这样,下面这段代码,将像你展示这种情形

import threading
import time

a = 0
def worker():
    time.sleep(1)
    global a
    for i in range(100000):
        a += 1


thread_lst = []
for i in range(5):
    t = threading.Thread(target=worker)
    thread_lst.append(t)

for t in thread_lst:
    t.start()

for t in thread_lst:
    t.join()

print(a)

启动5个线程,每个线程都会对变量a执行100000次加1操作, 最后print(a)时,最直观的猜想,a的值是500000,然而实际情况却并不是这样。

a最终的值会小于500000,这究竟是怎么一回事呢。

要想解释这个现象,就必须弄清楚,对变量加1这个操作是怎样完成的,在程序里,你只需要写a = a + 1 就可以完成一次对变量的加1操作,但在计算机内部,真实的加1过程却经历了很多

下图是一个线程对变量执行加1的过程
计算机对变量加1的过程

对变量执行加1操作,分为3个步骤

  1. 将变量的值读取到寄存器中
  2. 在寄存器中进行加1操作
  3. 将寄存器中的值写回到内存中

有了这个认识以后,再来看两个线程同时对变量a进行加1操作的过程

多线程同时对变量加1

线程A在t1时刻启动,线程B在t2时刻启动,问题就出在t2这个时刻,仔细观察示意图,你会注意到几点事实

  1. 内存里,a的值是1
  2. 线程A已经在寄存器里将1变为2
  3. 线程B将内存中的1读取到寄存器B中

这就是事情的全部真相,t2时刻,线程B在线程A还没有完成一次加1操作时,将内存中的数据读取到寄存器中。

t3时刻,线程A将2写回到内存中,而这一刻,线程B在寄存器中进行加1操作,寄存器中的值是2

t4时刻,线程B将2写回到内存,两个线程都执行了加1操作,可内存中变量a的值仍然是2。

通过两个线程执行加1操作过程的分析,相信你已经明白了,问题的根本在于对于我们所写的一行代码,计算机在执行时有很多操作,而这些操作之间会互相影响,这导致了线程不安全,那么怎么才能消除这种影响呢,咱们下回分解。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案