线程锁 死锁现象 递归锁 信号量 条件定时器 队列 线程池
锁是用来做什么的?
保证数据的安全的
GIL是干什么的?
锁线程
有了GIL还要锁干啥?
有了GIL还是会出现数据不安全的现象,所以还是要用锁
import time from threading import Thread,Lock n = 100 def func(lock): global n # n -= 1 with lock: tmp = n-1 # n-=1 time.sleep(0.1) n = tmp if __name__ == '__main__': l = [] lock = Lock() for i in range(100): t = Thread(target=func,args=(lock,)) t.start() l.append(t) for t in l:t.join() print(n)
dis模块的使用
import dis
n = 1
def func():
n = 100
n -= 1
dis.dis(func)
会出现线程不安全的两个条件
1.是全局变量
2.出现 += -=这样的操作
列表 字典
方法 l.append l.pop l.insert dic.update 都是线程安全的
l[0] += 1
d[k] += 1
死锁现象
# 科学家吃面问题
import time
from threading import Thread,Lock
# noodle_lock = Lock()
# fork_lock = Lock()
# 死锁不是时刻发生的,有偶然的情况整个程序都崩了
# 每一个线程之中不止一把锁,并且套着使用
# 如果某一件事情需要两个资源同时出现,那么不应该将这两个资源通过两把锁控制
# 而应看做一个资源
def eat1(name): noodle_lock.acquire() print('%s拿到面条了'%name) fork_lock.acquire() print('%s拿到叉子了'%name) print('%s开始吃面'%name) time.sleep(0.2) fork_lock.release() print('%s放下叉子了' % name) noodle_lock.release() print('%s放下面了' % name) def eat2(name): fork_lock.acquire() print('%s拿到叉子了' % name) noodle_lock.acquire() print('%s拿到面条了' % name) print('%s开始吃面' % name) time.sleep(0.2) noodle_lock.release() print('%s放下面了' % name) fork_lock.release() print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start() Thread(target=eat2,args=('wusir',)).start() Thread(target=eat1,args=('太白',)).start() Thread(target=eat2,args=('宝元',)).start()
lock = Lock() def eat1(name): lock.acquire() print('%s拿到面条了'%name) print('%s拿到叉子了'%name) print('%s开始吃面'%name) time.sleep(0.2) lock.release() print('%s放下叉子了' % name) print('%s放下面了' % name) def eat2(name): lock.acquire() print('%s拿到叉子了' % name) print('%s拿到面条了' % name) print('%s开始吃面' % name) time.sleep(0.2) lock.release() print('%s放下面了' % name) print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start() Thread(target=eat2,args=('wusir',)).start() Thread(target=eat1,args=('太白',)).start() Thread(target=eat2,args=('宝元',)).start()
互斥锁
# 无论在相同的线程还是不同的线程,都只能连续acquire一次
# 要想再acquire,必须先release
# 递归锁
# 在同一个线程中,可以无限次的acquire
# 但是要想在其他线程中也acquire,
# 必须现在自己的线程中添加和acquire次数相同的release
# rlock = RLock() # rlock.acquire() # rlock.acquire() # rlock.acquire() # rlock.acquire() # print('锁不住') # lock = Lock() # lock.acquire() # print('1') # lock.acquire() # print('2') # rlock = RLock() # def func(num): # rlock.acquire() # print('aaaa',num) # rlock.acquire() # print('bbbb',num) # rlock.release() # rlock.release() # # Thread(target=func,args=(1,)).start() # Thread(target=func,args=(2,)).start() import time noodle_lock = fork_lock = RLock() def eat1(name): noodle_lock.acquire() print('%s拿到面条了'%name) fork_lock.acquire() print('%s拿到叉子了'%name) print('%s开始吃面'%name) time.sleep(0.2) fork_lock.release() print('%s放下叉子了' % name) noodle_lock.release() print('%s放下面了' % name) def eat2(name): fork_lock.acquire() print('%s拿到叉子了' % name) noodle_lock.acquire() print('%s拿到面条了' % name) print('%s开始吃面' % name) time.sleep(0.2) noodle_lock.release() print('%s放下面了' % name) fork_lock.release() print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start() Thread(target=eat2,args=('wusir',)).start() Thread(target=eat1,args=('太白',)).start() Thread(target=eat2,args=('宝元',)).start()
信号量和池
# 进程池
# 有1000个任务
# 一个进程池中有5个进程
# 所有的1000个任务会多次利用这五个进程来完成任务
# 信号量
# 有1000个任务
# 有1000个进程/线程
# 所有的1000个任务由于信号量的控制,只能5个5个的执行
import time from threading import Semaphore,Thread def func(name,sem): sem.acquire() print(name,'start') time.sleep(1) print(name,'stop') sem.release() sem = Semaphore(5) for i in range(20): Thread(target=func,args=(i,sem)).start()
定时器