线程使用方法 锁(lock,Rlock),信号了(Semaphore),事件(Event),条件(Ccndition),定时器(timer)

时间:2021-07-28 00:22:55

2线程的使用方法
  (1)锁机制
       递归锁
           RLock()    可以有无止尽的锁,但是会有一把万能钥匙
       互斥锁:
           Lock()     一把钥匙配一把锁
       GIL:全局解释器锁
          锁的是线程,是CPython解释器上的一个锁,锁的是线程,意思是在同一时间只允许一个线程访问cpu
代码:

from threading import Thread,RLock
import time,os
# RLock是递归锁 --- 是无止尽的锁,但是所有锁都有一个共同的钥匙
# 想解决死锁,配一把公共的钥匙就可以了。

def man(l_tot,l_pap):
l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了
print('alex在厕所上厕所')
time.sleep(1)
l_pap.acquire()# 男的拿纸资源
print('alex拿到卫生纸了!')
time.sleep(0.5)
print('alex完事了!')
l_pap.release()# 男的先还纸
l_tot.release()# 男的还厕所

def woman(l_tot,l_pap):
l_pap.acquire() # 女的拿纸资源
print('小雪拿到卫生纸了!')
time.sleep(1)
l_tot.acquire() # 是女的获得厕所资源,把厕所锁上了
print('小雪在厕所上厕所')
time.sleep(0.5)
print('小雪完事了!')
l_tot.release() # 女的还厕所
l_pap.release() # 女的先还纸


if __name__ == '__main__':
l_tot = l_pap = RLock()
t_man = Thread(target=man,args=(l_tot,l_pap))
t_woman = Thread(target=woman,args=(l_tot,l_pap))
t_man.start()
t_woman.start()

死锁代码:
from threading import Thread,Lock
import time,os

def man(l_tot,l_pap):
l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了
print('alex在厕所上厕所')
time.sleep(1)
l_pap.acquire()# 男的拿纸资源
print('alex拿到卫生纸了!')
time.sleep(0.5)
print('alex完事了!')
l_pap.release()# 男的先还纸
l_tot.release()# 男的还厕所

def woman(l_tot,l_pap):
l_pap.acquire() # 女的拿纸资源
print('小雪拿到卫生纸了!')
time.sleep(1)
l_tot.acquire() # 是女的获得厕所资源,把厕所锁上了
print('小雪在厕所上厕所')
time.sleep(0.5)
print('小雪完事了!')
l_tot.release() # 女的还厕所
l_pap.release() # 女的先还纸


if __name__ == '__main__':
l_tot = Lock()
l_pap = Lock()
t_man = Thread(target=man,args=(l_tot,l_pap))
t_woman = Thread(target=woman,args=(l_tot,l_pap))
t_man.start()
t_woman.start()
 


  (2) 信号量:
      from threading import Semaphore
      去看多进程的信号量

代码:

from threading import Semaphore,Thread
import time

def func(sem,i):
sem.acquire()
print('第%s个人进入屋子'%i)
time.sleep(2)
print('第%s个人离开屋子'%i)
sem.release()

sem = Semaphore(20)
for i in range(20):
t = Thread(target=func,args=(sem,i))
t.start()



  (3) 事件
      from threading import Event
      去看多进程的事件机制

代码:

from threading import Thread,Event
import time,random

def conn_mysql(e,i):
count = 1
while count <= 3:
if e.is_set():
print('第%s个人连接成功!'%i)
break
print('正在尝试第%s次重新连接...'%(count))
e.wait(0.5)
count += 1

def check_mysql(e):
print('\033[42m 数据库正在维护 \033[0m')
time.sleep(random.randint(1,2))
e.set()


if __name__ == '__main__':
e = Event()
t_check = Thread(target=check_mysql,args=(e,))
t_check.start()

for i in range(10):
t_conn = Thread(target=conn_mysql,args=(e,i))
t_conn.start()



  (4) 条件
      from threading import Condition
      条件是让程序员自行去调度线程的一个机制
      # Condition涉及4个方法
      # acquire()
      # release()
      # wait()    是指让线程阻塞住
      # notify(int)  是指给wait发一个信号,让wait变成不阻塞
      #     int是指,你要给多少给wait发信号

代码:

from threading import Thread,Condition
import time
# Condition涉及4个方法
# acquire()
# release()
# wait() 是指让线程阻塞住
# notify(int) 是指给wait发一个信号,让wait变成不阻塞
# int是指,你要给多少给wait发信号


def func(con,i):
con.acquire()
con.wait()# 线程执行到这里,会阻塞住,等待notify发送信号,来唤醒此线程
con.release()
print('第%s个线程开始执行了!'%i)

if __name__ == '__main__':
con = Condition()
for i in range(10):
t = Thread(target=func,args=(con,i))
t.start()
while 1:
num = int(input(">>>"))
con.acquire()
con.notify(num)# 发送一个信号给num个正在阻塞在wait的线程,让这些线程正常执行
con.release()
另一种解释是:
from threading import Condition,Thread
import time

def func(con,i):
con.acquire()# 主线程和10个子线程都在抢夺递归锁的一把钥匙。
# 如果主线程抢到钥匙,主线程执行while 1,input,然后notify发信号,还钥匙。但是,此时如果主线程执行特别快
# 极有可能接下来主线程又会拿到钥匙,那么此时哪怕其他10个子线程的wait接收到信号,但是因为没有拿到钥匙,所以其他子线程还是不会执行
con.wait()
print('第%s个线程执行了'%i)
con.release()
con = Condition()
for i in range(10):
t = Thread(target=func,args = (con,i))
t.start()
while 1:
# print(123)
con.acquire()
num = input('>>>')
con.notify(int(num))
con.release()
time.sleep(0.5)

# 条件 涉及 4个方法:
# con.acquire()
# con.release()
# con.wait() # 假设有一个初始状态为False,阻塞。一旦接受到notify的信号后,变为True,不再阻塞
# con.notify(int) 给wait发信号,发int个信号,会传递给int个wait,让int个线程正常执行
 



  (5) 定时器
      from threading import Timer
          # Timer(time,func)
          # time:睡眠的时间,以秒为单位
          # func:睡眠时间之后,需要执行的任务

代码:

from threading import Timer# 定时器

def func():
print('就是这么nb!')

Timer(2.5,func).start()
# Timer(time,func)
# time:睡眠的时间,以秒为单位
# func:睡眠时间之后,需要执行的任务