3.2.2 线程锁

线程锁(Mutex)互斥锁

以上演示的是GIL锁,GIL锁只能保证同一时刻,CPU上只有一条线程在运行,但不能保证同一时刻只有一条线程在修改数据,要想实现这个效果,我们要加上另一把锁,线程锁。示例如下:

import threading
import time

start_time = time.time()
def run(n):
    lock.acquire()    #获取线程锁对象
    global num
    # time.sleep(1)
    num += 1
    lock.release()    #释放线程锁

lock = threading.Lock()    #示例化一个线程锁对象
num = 0
t_l = []    #存放线程
for i in range(10):
    t = threading.Thread(target=run, args=('t-%s' % i, ))
    t.start()
    t_l.append(t)    #为了不阻塞其他线程的启动,先放在列表里,最后join

for t in t_l:    #循环线程列表,执行所有线程
    t.join()

print('All threads have ran down!', threading.current_thread(), threading.activeCount())
time.sleep(0)
#current_thread显示当前线程
#activeCount显示活动的线程数
print('Num: ', num)
print('Total Cost: ', time.time() - start_time)

运行结果

All threads have ran down! <_MainThread(MainThread, started 7268)> 1
Num:  10
Total Cost:  0.0026278495788574

这次结果就对了,但此时实际上是串行运行。

递归锁

说白了就是在一个大锁中还要再包含子锁

示例

import threading


def run1():
    print("grab the first part data")
    lock.acquire()    #第二把锁
    global num    #声明全局变量,让全局变量num可以在run1()内进行修改
    num += 1
    lock.release()    #run1()执行完毕,释放第二把锁
    return num    #返回run3()num的值


def run2():
    print("grab the second part data")
    lock.acquire()
    global num2
    num2 += 2
    lock.release()
    return num2


def run3():
    lock.acquire()    #加递归锁,第一把锁
    res = run1()    #执行run1()函数
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()    #释放第一把锁
    print(res, res2)


if __name__ == '__main__':

    num, num2 = 0, 0
    lock = threading.RLock()    #RLock递归锁,如果是Lock,程序会陷入死循环
    for i in range(10):
        t = threading.Thread(target=run3)    #每循环一次,启动一条线程执行run3()
        t.start()

while threading.active_count() != 1:    #循环条件,活动线程数为1时循环结束
    print('From Primary Thread: Thread left: ', threading.active_count())
else:
    print('All threads are done!')
    print('Num1: %d, Num2: %d' %(num, num2))

输出结果

grab the first part data
--------between run1 and run2-----
grab the second part data
1 2
grab the first part data
--------between run1 and run2-----
grab the second part data
2 4
grab the first part data
--------between run1 and run2-----
grab the second part data
3 6
grab the first part data
--------between run1 and run2-----
grab the second part data
4 grab the first part data
--------between run1 and run2-----
8grab the second part data

5grab the first part data 
10--------between run1 and run2-----

grab the second part data
6 grab the first part data12

--------between run1 and run2-----
grab the second part data
7grab the first part data 
14From Primary Thread: Thread left: --------between run1 and run2-----
 
5grab the second part data

From Primary Thread: Thread left:  4
From Primary Thread: Thread left:  8grab the first part data4 

16--------between run1 and run2-----From Primary Thread: Thread left: 

 grab the second part data4

9grab the first part data From Primary Thread: Thread left: 
18 --------between run1 and run2-----
3

grab the second part dataFrom Primary Thread: Thread left: 
 102
From Primary Thread: Thread left:   202

All threads are done!
Num1: 10, Num2: 20

上面示例中

lock = threading.RLock()

这里如果使用Lock,而不是RLock,程序会陷入死循环。



你可能感兴趣的:(3.2.2 线程锁)