Whoosy's Blog

藏巧于拙 用晦而明 寓清于浊 以屈为伸

0%

线程不安全一例

编码不易,转载请注意出处!

python多线程虽然有GIL管着,在IO密集型任务的时候,还是可以用的。
本文给出一个很简单的线程不安全的示例,说明一个事情:凡是共享的资源,都要自己加锁控制,不要以为python的每一行脚本都是原子操作,虽然python自定的确定义了一些原子操作,但是不要去依赖,如果哪一天python解释器修改了内部机制,你的代码就会崩溃;对于共享资源,无论有几个修改线程,加把锁更安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from threading import Thread, Lock

number = 0

def target():
global number
for _ in range(1000000):
number += 1

thread_01 = Thread(target=target)
thread_02 = Thread(target=target)
thread_01.start()
thread_02.start()

thread_01.join()
thread_02.join()

print(number)

两个线程,并发对一个全局变量进行+1操作,我们预期的结果是2000000,但是不是,每一次运行都不是,而且还不一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ python thread_not_safe.py
1391219

$ python thread_not_safe.py
1241460

$ python thread_not_safe.py
1210578

$ python thread_not_safe.py
1221867

$ python thread_not_safe.py
1136912

加锁方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from threading import Thread, Lock

number = 0
mutex = Lock()

def target():
global number
for _ in range(1000000):
mutex.acquire()
number += 1
mutex.release()

thread_01 = Thread(target=target)
thread_02 = Thread(target=target)
thread_01.start()
thread_02.start()

thread_01.join()
thread_02.join()

print(number)

这样每次运行代码得到的结果都是2000000!