zoukankan      html  css  js  c++  java
  • python-day36--并发编程之多线程

    十三、死锁、递归锁

      1.所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

     1 from threading import Lock,Thread
     2 import time
     3 mutexB=Lock()
     4 mutexA=Lock()
     5 class MyThread(Thread):
     6     def run(self):
     7         self.f1()
     8         self.f2()
     9 
    10     def f1(self):
    11         mutexA.acquire()
    12         print('%s拿到了A锁' %self.name)
    13         mutexB.acquire()
    14         print('%s拿到了B锁' %self.name)
    15         mutexB.release()
    16         mutexA.release()
    17 
    18     def f2(self):
    19         mutexB.acquire()
    20         print('%s拿到了B锁' %self.name)
    21         time.sleep(1)
    22         mutexA.acquire()
    23         print('%s拿到了A锁' %self.name)
    24         mutexA.release()
    25         mutexB.release()
    26 
    27 if __name__ == '__main__':
    28     for i in range(10):
    29         t=MyThread()
    30         t.start()
    31 
    32 # 结果
    33 # Thread-1拿到了A锁
    34 # Thread-1拿到了B锁
    35 # Thread-1拿到了B锁
    36 # Thread-2拿到了A锁
    37 。。。。 卡住了
    View Code

      2.解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

    这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:

     1 from threading import Thread,RLock
     2 import time
     3 mutexB=mutexA=RLock()
     4 class MyThread(Thread):
     5     def run(self):
     6         self.f1()
     7         self.f2()
     8 
     9     def f1(self):
    10         mutexA.acquire()
    11         print('33[32m%s 拿到A锁' %self.name)
    12         mutexB.acquire()
    13         print('33[45m%s 拿到B锁' %self.name)
    14         mutexB.release()
    15         mutexA.release()
    16 
    17     def f2(self):
    18         mutexB.acquire()
    19         print('33[32m%s 拿到B锁' %self.name)
    20         time.sleep(1)
    21         mutexA.acquire()
    22         print('33[45m%s 拿到A锁' %self.name)
    23         mutexA.release()
    24         mutexB.release()
    25 
    26 if __name__ == '__main__':
    27     for i in range(2):
    28         t=MyThread()
    29         t.start()
    30 
    31 # 结果:
    32 # Thread-1 拿到A锁
    33 # Thread-1 拿到B锁
    34 # Thread-1 拿到B锁
    35 # Thread-1 拿到A锁
    36 # Thread-2 拿到A锁
    37 # Thread-2 拿到B锁
    38 # Thread-2 拿到B锁
    39 # Thread-2 拿到A锁
    View Code

    十四、信号量Semaphore

      Semaphore管理一个内置的计数器,
      每当调用acquire()时内置计数器-1;
      调用release() 时内置计数器+1;
      计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

     1 from threading import Thread,Semaphore,currentThread
     2 import time,random
     3 sm=Semaphore(5)    #限制最大连接数为5
     4 def task():
     5     sm.acquire()
     6     print('%s 上厕所' %currentThread().getName())
     7     time.sleep(random.randint(1,3))
     8     print('%s 走了' %currentThread().getName())
     9     sm.release()
    10 if __name__ == '__main__':
    11     for i in range(20):
    12         t=Thread(target=task)
    13         t.start()
    View Code

      与进程池是完全不同的概念,进程池Pool(4),最大只能产生4个进程,而且从头到尾都只是这    四个进程,不会产生新的,而信号量是产生一堆线程/进程

    十五、Event事件

    1 event.isSet():返回event的状态值;
    2 
    3 event.wait():如果 event.isSet()==False将阻塞线程;
    4 
    5 event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
    6 
    7 event.clear():恢复event的状态值为False。
     1 from threading import Thread,Event,currentThread
     2 import time
     3 e=Event()
     4 
     5 def traffic_lights():
     6     time.sleep(5)
     7     e.set()
     8 
     9 def car():
    10     print('33[45m%s 等' %currentThread().getName())
    11     e.wait()
    12     print('33[45m%s 跑' %currentThread().getName())
    13 
    14 
    15 if __name__ == '__main__':
    16     for i in range(10):
    17         t=Thread(target=car)
    18         t.start()
    19     traffic_thread=Thread(target=traffic_lights)
    20     traffic_thread.start()
    例子
     1 from threading import Thread,Event,currentThread
     2 import time
     3 e=Event()
     4 def conn_mysql():
     5     count=1
     6     while not e.is_set():
     7         if count > 3:
     8             raise ConnectionError('尝试链接的次数过多')
     9         print('33[45m%s 第%s次尝试' %(currentThread().getName(),count))
    10         e.wait(timeout=1)
    11         count+=1
    12     print('33[45m%s 开始链接' %currentThread().getName())
    13 
    14 def check_mysql():
    15     print('33[45m%s 检测mysql...' %currentThread().getName())
    16     time.sleep(4)     #超时了
    17     e.set()
    18 if __name__ == '__main__':
    19     t=Thread(target=check_mysql)
    20     t.start()
    21     for i in range(3):
    22         t=Thread(target=conn_mysql)
    23         t.start()
    重要的例子

    十六、定时器

    1 from threading import Timer
    2 
    3 def hello(n):
    4     print("hello, world",n)
    5 
    6 t = Timer(3, hello,args=(123,))   #3秒后运行hello函数, 可以传参数
    7 t.start()
    View Code

    十七、线程queue

      queue队列 :使用import queue,用法与进程Queue一样

      queue.Queue      #先进先出   #队列

     1 import queue
     2 
     3 q=queue.Queue()
     4 q.put('first')
     5 q.put('second')
     6 q.put('third')
     7 
     8 print(q.get())
     9 print(q.get())
    10 print(q.get())
    11 '''
    12 结果(先进先出):
    13 first
    14 second
    15 third
    16 '''
    View Code

      queue.LifoQueue     #last in fisrt out  #堆栈

     1 import queue
     2 
     3 q=queue.LifoQueue()
     4 q.put('first')
     5 q.put('second')
     6 q.put('third')
     7 
     8 print(q.get())
     9 print(q.get())
    10 print(q.get())
    11 '''
    12 结果(后进先出):
    13 third
    14 second
    15 first
    16 '''
    View Code

      queue.PriorityQueue     #存储数据时可设置优先级的队列

     1 import queue
     2 
     3 q=queue.PriorityQueue()
     4 #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
     5 q.put((20,'a'))
     6 q.put((10,'b'))
     7 q.put((30,'c'))
     8 
     9 print(q.get())
    10 print(q.get())
    11 print(q.get())
    12 '''
    13 结果(数字越小优先级越高,优先级高的优先出队):
    14 (10, 'b')
    15 (20, 'a')
    16 (30, 'c')
    17 '''
    View Code
  • 相关阅读:
    移动端兼容
    三点优化
    面向对象(一)
    BootCDN和npm
    分页逻辑
    多物体运动框架
    兼容样式
    省略
    行内元素在水平和垂直排列的时候会有间距
    [Swift]LeetCode1053.交换一次的先前排列 | Previous Permutation With One Swap
  • 原文地址:https://www.cnblogs.com/liuwei0824/p/7453938.html
Copyright © 2011-2022 走看看