首页 » 编程 » Python » Python学习 » 网络编程进阶 » 正文

线程-互斥锁

从例子出发,来看需求:

n=100, 启动100个线程,每个线程对n-1,运行完后输出最后结果。

 

来看我们一般的做法:

这儿已n=3为例:

from threading import Thread
import time

n = 3


def task():
    global n
    temp = n
    time.sleep(0.1)
    n = temp - 1


if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t1.join()
    t2.start()
    t2.join()
    t3.start()
    t3.join()
    print("主,n=%s" % n)

输出:

主,n=0

这里达到了我们的要求,但是这是串行了,并没有提高效率。

 

改进一下,其实也是串行:

from threading import Thread
import time

n = 3


def task():
    global n
    temp = n
    time.sleep(0.1)
    n = temp - 1


if __name__ == '__main__':
    for i in range(3):
        t = Thread(target=task)
        t.start()
        t.join()
    print("主,n=%s" % n)

输出:

主,n=0

这里其实也是串行,只不过写成了for循环。

 

来看看Teacher讲的例子:

from threading import Thread
import time

n = 100


def task():
    global n
    temp = n
    time.sleep(0.1)
    n = temp - 1


if __name__ == '__main__':
    t_l = []
    for i in range(100):
        t = Thread(target=task)
        t_l.append(t)
        t.start()
    for t in t_l:
        t.join()
    print("主", n)

输出:

主 99

为什么会输出 99 呢 ?通过我的前两个串行的例子应该可以知道,要想做到每个线程都减1的情况,处理使用互斥锁,就只能写为串行,而这个例子咋眼一看没啥问题,实际上是有问题的,程序启动100个线程就开启了,当第1个线程启动后,就执行了真正的代码 global n 和 temp =n, 随后开始睡觉,睡的这期间其他的99个线程也是同样的进入到睡觉状态,当第1个线程执行完后便将temp -1 的结果给了n,也就是99,由于其他99个线程都经历了睡觉等待,所以都拿到的是temp=100,在睡觉完成后,都是执行的 temp – 1 即将99给到n,所以最后输出n为99。

需要注意的是,这里不是有join吗,为啥不是一个线程执行结束后再执行下一个线程呢,因为join在100个线程start之后,并不是每启动1个线程就开始join所以是没有用的,这里也是启动的100个join,只是保证100个线程后运行结束了再运行主线程。

 

那么怎么在不串行的情况下来实现这个功能呢,那就使用互斥锁:

from threading import Thread, Lock
import time

n = 100


def task():
    global n
    mutex.acquire()
    temp = n
    time.sleep(0.1)
    n = temp - 1
    mutex.release()


if __name__ == '__main__':
    mutex = Lock()
    t_l = []
    for i in range(100):
        t = Thread(target=task)
        t_l.append(t)
        t.start()
    for t in t_l:
        t.join()
    print("主", n)

输出:

主 0

结果达到了我们的需求,同时牺牲了一定的效率,但保证了数据安全,互斥锁的使用使得程序内部只是局部串行,而不是全部的串行,只在需要的地方加锁,任务完成后解锁,让下一个任务继续执行。

 

 

 

赞 (0)

发表评论

*