Python 线程同步锁, 信号量
程序员文章站
2022-04-16 09:02:42
同步锁 原因: 第一个程序中,num = 1 这种写法,程序执行动作太快(完成这个动作在 cup 切换的时间内) 第二个程序中,把 num = 1 , 加入了 sleep 时间,100个线程存在没有执行完就进行了切换,导致全局的 num 没有正常返回。引用下大神的图发现总结得非常好: 在上面的例子中 ......
同步锁
import time, threading def addNum(): global num num -= 1 num = 100 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: t.join() print('final num:', num) 运行结果: final num: 0
import time, threading def addNum(): global num #num -= 1 tmp = num time.sleep(0.00001) num = tmp - 1 num = 100 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: t.join() print('final num:', num) 运行结果: final num: 93 或 final num: 91 或 final num: 94
原因:
第一个程序中,num -= 1 这种写法,程序执行动作太快(完成这个动作在 cup 切换的时间内)
第二个程序中,把 num -= 1 , 加入了 sleep 时间,100个线程存在没有执行完就进行了切换,导致全局的 num 没有正常返回。引用下大神的图发现总结得非常好:
在上面的例子中 使用 join 方法会把整个线程停住,造成了串行,失去了多线程的意义,我们只需要在涉及到计算公共数据的时候串行执行即可。
使用同步锁处理计算公共的数据
import time, threading def addNum(): global num lock.acquire() tmp = num time.sleep(0.00001) num = tmp - 1 lock.release() num = 100 lock = threading.Lock() thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: t.join() print('final num:', num) 运算结果: final num: 0
线程死锁和递归锁
import threading, time class myThread(threading.Thread): def doA(self): lockA.acquire() print(self.name, "gotlockA", time.ctime()) time.sleep(3) lockB.acquire() print(self.name, "gotlockB", time.ctime()) lockB.release() lockA.release() def doB(self): lockB.acquire() print(self.name, "gotlockB", time.ctime()) time.sleep(2) lockA.acquire() print(self.name, "gotlockA", time.ctime()) lockA.release() lockB.release() def run(self): self.doA() self.doB() if __name__ == '__main__': lockA = threading.Lock() lockB = threading.Lock() threads = [] for i in range(5): threads.append(myThread()) for t in threads: t.start() for t in threads: t.join() #运行结果: Thread-1 gotlockA Sat Jul 28 15:09:31 2018 Thread-1 gotlockB Sat Jul 28 15:09:34 2018 Thread-1 gotlockB Sat Jul 28 15:09:34 2018 Thread-2 gotlockA Sat Jul 28 15:09:34 2018
使用递归锁
import threading, time class myThread(threading.Thread): def doA(self): lock.acquire() print(self.name, "gotlockA", time.ctime()) time.sleep(3) lock.acquire() print(self.name, "gotlockB", time.ctime()) lock.release() lock.release() def doB(self): lock.acquire() print(self.name, "gotlockB", time.ctime()) time.sleep(2) lock.acquire() print(self.name, "gotlockA", time.ctime()) lock.release() lock.release() def run(self): self.doA() self.doB() if __name__ == '__main__': lock = threading.RLock() threads = [] for i in range(5): threads.append(myThread()) for t in threads: t.start() for t in threads: t.join() 运行结果: Thread-1 gotlockA Sat Jul 28 15:19:35 2018 Thread-1 gotlockB Sat Jul 28 15:19:38 2018 Thread-1 gotlockB Sat Jul 28 15:19:38 2018 Thread-1 gotlockA Sat Jul 28 15:19:40 2018 Thread-3 gotlockA Sat Jul 28 15:19:40 2018 Thread-3 gotlockB Sat Jul 28 15:19:43 2018 Thread-3 gotlockB Sat Jul 28 15:19:43 2018 Thread-3 gotlockA Sat Jul 28 15:19:45 2018 Thread-5 gotlockA Sat Jul 28 15:19:45 2018 Thread-5 gotlockB Sat Jul 28 15:19:48 2018 Thread-5 gotlockB Sat Jul 28 15:19:48 2018 Thread-5 gotlockA Sat Jul 28 15:19:50 2018 Thread-4 gotlockA Sat Jul 28 15:19:50 2018 Thread-4 gotlockB Sat Jul 28 15:19:53 2018 Thread-4 gotlockB Sat Jul 28 15:19:53 2018 Thread-4 gotlockA Sat Jul 28 15:19:55 2018 Thread-2 gotlockA Sat Jul 28 15:19:55 2018 Thread-2 gotlockB Sat Jul 28 15:19:58 2018 Thread-2 gotlockB Sat Jul 28 15:19:58 2018 Thread-2 gotlockA Sat Jul 28 15:20:00 2018
信号量
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1,计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)。
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。
import threading, time class myThread(threading.Thread): def run(self): if semaphore.acquire(): print(self.name) time.sleep(5) semaphore.release() if __name__ == "__main__": semaphore = threading.Semaphore(5) thrs = [] for i in range(20): thrs.append(myThread()) for t in thrs: t.start() #运行结果: Thread-1 Thread-2 Thread-3 Thread-4 Thread-5 Thread-6 Thread-7 Thread-9 Thread-10 Thread-8 Thread-11 Thread-13 Thread-14 Thread-12 Thread-15 Thread-18 Thread-16 Thread-17 Thread-19 Thread-20
import threading, time class myThread(threading.Thread): def run(self): if semaphore.acquire(): print(self.name) time.sleep(5) semaphore.release() if __name__ == "__main__": semaphore = threading.BoundedSemaphore(5) thrs = [] for i in range(20): thrs.append(myThread()) for t in thrs: t.start() #运行结果: Thread-1 Thread-2 Thread-3 Thread-4 Thread-5 Thread-6 Thread-8 Thread-10 Thread-9 Thread-7 Thread-12 Thread-14 Thread-15 Thread-13 Thread-11 Thread-16 Thread-17 Thread-20 Thread-19 Thread-18