# 并发&并行 同步&异步 GIL 任务 同步锁 死锁 递归锁
# 并发:是指系统具有处理多个任务(动作)的能力
# 并行:是指系统具有 同时 处理多个任务(动作)的能力
# 同步:当进程执行到一个IO(等待外部数据)的时候,需要等待外部数据接收完
# 异步:当进程执行到一个IO(等待外部数据)的时候,不需要等待外部数据接收完,还可以做其它的处理
# GIL: 全局解释器锁 在python中,无论你启多少个线程,你有多少个cpu,python在执行的时候在同一时刻只请允许一个线程运行
# 任务:IO密集型(python的多线程是有意义的,或使用多进程+协程) 计算密集型(python的多线程就不推荐,python就不适用了)
# 同步锁
import threading, time
num = 100
def sub():
global num
temp = num
time.sleep(0.00001)
num = temp - 1
l = [] # 定义一个空列表
for i in range(100): # 循环100次
t = threading.Thread(target=sub) # 通过循环创建100个线程t对象并放入列表中
t.start()
l.append(t)
for t in l: # 循环列表,让每一个线程对象t执行join()
t.join()
print(num) # 99 居然不是0,问题在哪里?
# 因为此时是IO操作,当第一个线程取到100后要睡1秒,这时还没有减1,这时第二个线程又来取值,值还是100,只要cpu执行速度越快,所有的线程来取值时都是100,意味着100个线程都拿到num为100
# 如果sleep(0.00001),这时最终值又会变为92。这里的值与cpu调度的各线程IO操作的时间有关,sleep时间越短,各个线程拿到num为100时的情况就越少
# 解决方法,加上同步锁,在同一时间只允许一个线程对num操作
import threading, time
num = 100
def sub():
global num
lock.acquire() # 加锁
temp = num
time.sleep(0.00001)
num = temp - 1
lock.release() # 解锁
l = [] # 定义一个空列表
lock = threading.Lock() # 创建同步锁
for i in range(100): # 循环100次
t = threading.Thread(target=sub) # 通过循环创建100个线程t对象并放入列表中
t.start()
l.append(t)
for t in l: # 循环列表,让每一个线程对象t执行join()
t.join()
print(num) # 0
# 一个死锁的例子 第一个线程需要A锁(A锁已被第二个线程占用),第二个线程需要B锁(B锁已被第一个线程占用)。结果谁也不让造成死锁
import threading, time
class MyThread(threading.Thread):
def actionA(self):
A.acquire()
print(self.name, 'gotA', time.ctime())
time.sleep(2)
B.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(2)
B.release()
A.release()
def actionB(self):
B.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(2)
A.acquire()
print(self.name, 'gotA', time.ctime())
time.sleep(2)
A.release()
B.release()
def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
A = threading.Lock()
B = threading.Lock()
l = []
for i in range(5):
t = MyThread()
t.start()
l.append(t)
for i in l:
t.join()
print('end...')
# 解决死锁的方案,使用递归锁
import threading, time
class MyThread(threading.Thread):
def actionA(self):
r_lock.acquire()
print(self.name, 'gotA', time.ctime())
time.sleep(2)
r_lock.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(2)
r_lock.release()
r_lock.release()
def actionB(self):
r_lock.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(2)
r_lock.acquire()
print(self.name, 'gotA', time.ctime())
time.sleep(2)
r_lock.release()
r_lock.release()
def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
r_lock = threading.RLock() # 这里创建的是递归锁,将原来的两把锁AB换成一把锁
# 哪个线程拿到r_lock锁,只有等它完全释放后,其它的线程才能再拿这个锁
l = []
for i in range(5):
t = MyThread()
t.start()
l.append(t)
for i in l:
t.join()
print('end...')