淘先锋技术网

首页 1 2 3 4 5 6 7

无锁多线程案例

import threading
import time

num = 100

def fun_sub():
    global num
    num2 = num
    time.sleep(0.001)
    num = num2 - 1


if __name__ == '__main__':
    print('开始测试同步锁 at %s' % time.ctime())

    thread_list = []
    for thread in range(100):
        t = threading.Thread(target=fun_sub)
        t.start()
        thread_list.append(t)

    for t in thread_list:
        t.join()

    print(f"num is {num}")
    print(f"结束测试同步锁 at {time.ctime()}")

通过 100 个线程分别调用 fun_sub() 函数来修改公共变量 num,会产生当某线程在 time.sleep(0.001) 挂起时,其之后的线程 num2 = num 并没有拿到该线程的结果 num 值 进行错位运算,导致最终误差:

开始测试同步锁 at Fri Aug 14 18:34:15 2020
num is 94
结束测试同步锁 at Fri Aug 14 18:34:15 2020

理论上 100 个线程对 num 先后 -1 结果应该是 0 的。

为线程添加同步锁

同步锁的作用是只允许一个线程来操作共享资源:

import threading
import time

num = 100

def fun_sub():
    global num
    lock.acquire()
    print("-----加锁-----")
    print("现在操作共享资源的线程名字是:", t.name)
    num2 = num
    time.sleep(0.001)
    num = num2 - 1
    lock.release()
    print("-----释放锁-----")


if __name__ == '__main__':
    print('开始测试同步锁 at %s' % time.ctime())

    lock = threading.Lock()

    thread_list = []
    for thread in range(100):
        t = threading.Thread(target=fun_sub)
        t.start()
        thread_list.append(t)

    for t in thread_list:
        t.join()

    print(f"num is {num}")
    print(f"结束测试同步锁 at {time.ctime()}")

注意加了锁之后,只允许单线程来访问共享数据,那么多线程意义在哪呢?注意锁的作用对象是共享数据,但多线程并非时刻都在访问共享数据,所以我们要把锁加在特定共享数据处,以减小对多线程代码的副作用影响。