Python 多线程-线程的同步锁&死锁
并发:指的是系统具有执行多个任务(动作)的能力
并行:指的是系统具有同时执行多个任务(动作)的能力, 也就是同一时刻执行多个任务。(同一时刻)
同步:当执行一个IO操作的时候(等待一个外部数据的时候),等待
异步:当执行一个IO操作的时候(等待一个外部数据的时候),不等待,继续执行其他,直到接收到外部数据的时候再回来处理
多线程带来的数据混乱问题:
import threading import time ticket = 100 def sally_ticket(): """ 当多个线程同时得到 temp =ticket后,此时大家得到的数是一样的; 然后发送阻塞,当有一个线程结束阻塞后将ticket-1, 此时 ticket已经发生变化,但是其他还没有完成阻塞的线程拿到的temp还没有改变,这样就造成数据混乱了。 :return: """ global ticket temp = ticket time.sleep(0.001) ticket = temp - 1 if __name__ == '__main__': threads = [] for i in range(100): t = threading.Thread(target=sally_ticket, args=()) t.start() threads.append(t) for t in threads: t.join() print(ticket)
解决办法,加同步锁(将需要操作共同数据的代码块保护起来,使之变成串行)
import threading import time ticket = 100 lock=threading.Lock() # 得到锁 def sally_ticket(): global ticket lock.acquire() # 加锁 temp = ticket time.sleep(0.01) ticket = temp - 1 lock.release() # 解锁 if __name__ == '__main__': threads = [] for i in range(100): t = threading.Thread(target=sally_ticket, args=()) t.start() threads.append(t) for t in threads: t.join() print(ticket)
死锁:
在线程之间共享资源的时候,双方的锁均没有被释放,各自等待对方的锁释放。
import threading import time class MyThread(threading.Thread): def __init__(self, thread_name): threading.Thread.__init__(self) self.thread_name = thread_name def action1(self): lock1.acquire() print('%s 拿到 lock1锁' % self.thread_name) time.sleep(2) lock2.acquire() print('%s 拿到 lock2锁' % self.thread_name) time.sleep(2) lock1.release() lock2.release() def action2(self): lock2.acquire() print('%s 拿到 lock2锁' % self.thread_name) time.sleep(2) lock1.acquire() print('%s 拿到 lock1锁' % self.thread_name) time.sleep(2) lock2.release() lock1.release() def run(self): self.action1() self.action2() if __name__ == '__main__': lock1 = threading.Lock() lock2 = threading.Lock() threads = [] for i in range(5): t = MyThread('thread%s'%i) t.start() threads.append(t) for i in threads: i.join() print('==========================================')
解决方法使用递归锁:
递归锁,就是只有一把锁,这把锁每次加锁的时候里面的计数器就加1,直到里面的计算器清零(释放锁),其他的线程才可以得到这把递归锁。
import threading import time class MyThread(threading.Thread): def __init__(self, thread_name): threading.Thread.__init__(self) self.thread_name = thread_name def action1(self): lock.acquire() print('%s 拿到 lock锁' % self.thread_name) time.sleep(2) lock.acquire() print('%s 拿到 lock锁' % self.thread_name) time.sleep(2) print('%s 释放 lock锁' % self.thread_name) lock.release() print('%s 释放 lock锁' % self.thread_name) lock.release() def action2(self): lock.acquire() print('%s 拿到 lock锁' % self.thread_name) time.sleep(2) lock.acquire() print('%s 拿到 lock锁' % self.thread_name) time.sleep(2) print('%s 释放 lock锁' % self.thread_name) lock.release() print('%s 释放 lock锁' % self.thread_name) lock.release() def run(self): self.action1() self.action2() if __name__ == '__main__': lock= threading.RLock() # 递归锁 threads = [] for i in range(5): t = MyThread('thread%s'%i) t.start() threads.append(t) for i in threads: i.join() print('==========================================')