zoukankan      html  css  js  c++  java
  • Python并发编程-线程同步(线程安全)

          Python并发编程-线程同步(线程安全)

                           作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

      线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直到该线程完成对数据的操作。

     

    一.Event

    1>.Event的常用方法

    Event事件,是线程通信机制中最简单的实现,使用一个内部的标记flag,通过flage的True或False的变化来进行操作。
    
    常用方法如下:
        set():
        标记为True。
    clear():     标记设置为Flase。
    is_set():
        查询标记是否为True。
    wait(timeout=None):
        设置等待标记为True的时长,None为无线等待。等到返回True,未等到超时了返回False。

    2>.Event使用案例

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 
     7 from threading import Event,Thread
     8 import logging
     9  
    10 FORMAT = "%(asctime)s %(threadName)s %(thread)s %(message)s"
    11 logging.basicConfig(format=FORMAT,level=logging.INFO)
    12 
    13 def boss(event:Event):
    14     logging.info("I'm boss,waiting for U")
    15     event.wait()        #阻塞等待,直到event被标记为Ture
    16     logging.info("Good Job.")
    17 
    18 def worker(event:Event,count=10):
    19     logging.info("I'm working for U.")
    20     cups = []
    21     while not event.wait(0.5):      #使用wait等待0.5秒(相当于"time.sleep(0.5)"),若规定事件内event依旧标记依旧没有设置为True,则返回False
    22         logging.info("make 1 cup")
    23         cups.append(1)
    24         if len(cups) >= count:
    25             event.set()             #将标记设置为True
    26             break
    27     logging.info("I finished my job.cups={}".format(cups))
    28 
    29 event = Event()
    30 print(event.is_set())               #event实例的标记默认为False
    31 
    32 b = Thread(target=boss,name="boss",args=(event,))
    33 w = Thread(target=worker,name="worker",args=(event,))
    34 b.start()
    35 w.start()
    2019-11-23 14:54:53,177 boss 10916 I'm boss,waiting for U
    2019-11-23 14:54:53,178 worker 15672 I'm working for U.
    False
    2019-11-23 14:54:53,678 worker 15672 make 1 cup
    2019-11-23 14:54:54,179 worker 15672 make 1 cup
    2019-11-23 14:54:54,680 worker 15672 make 1 cup
    2019-11-23 14:54:55,180 worker 15672 make 1 cup
    2019-11-23 14:54:55,680 worker 15672 make 1 cup
    2019-11-23 14:54:56,181 worker 15672 make 1 cup
    2019-11-23 14:54:56,681 worker 15672 make 1 cup
    2019-11-23 14:54:57,181 worker 15672 make 1 cup
    2019-11-23 14:54:57,681 worker 15672 make 1 cup
    2019-11-23 14:54:58,182 worker 15672 make 1 cup
    2019-11-23 14:54:58,182 worker 15672 I finished my job.cups=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    2019-11-23 14:54:58,182 boss 10916 Good Job.
    以上代码执行结果戳这里

    3>.定时器Timer(延迟执行)

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import threading
     7 import logging
     8 import time
     9 
    10 FORMAT = "%(asctime)s %(threadName)s %(thread)s %(message)s"
    11 logging.basicConfig(level=logging.INFO,format=FORMAT)
    12 
    13 def worker():
    14     logging.info("working")
    15     time.sleep(2)
    16 
    17 """
    18     Timer是线程Thread的子类,Timer实例内部提供了一个finished属性,该属性是Event对象。
    19     Timer是线程Thread的子类,就是线程类,具有线程的能力和特征。
    20     它的实例时能够延时执行目标函数的线程,在真正执行目标函数之前,都可以cancel它。
    21     cacel方法本质使用Event类实现。这并不是说,线程提供了取消的方法。
    22 """
    23 t = threading.Timer(4,worker)             #当t对象调用start方法后,等待4秒后执行worker函数
    24 t.setName("timer")
    25 
    26 t.start()
    27 # t.cancel()                               #本质上是在worker函数执行前对finished属性set方法操作,从而跳过了worker函数执行,达到了取消的效果。
    28 
    29 for _ in range(10):
    30     print(threading.enumerate())
    31     time.sleep(1)
    [<_MainThread(MainThread, started 5332)>, <Timer(timer, started 6656)>]
    [<_MainThread(MainThread, started 5332)>, <Timer(timer, started 6656)>]
    [<_MainThread(MainThread, started 5332)>, <Timer(timer, started 6656)>]
    [<_MainThread(MainThread, started 5332)>, <Timer(timer, started 6656)>]
    [<_MainThread(MainThread, started 5332)>, <Timer(timer, started 6656)>]
    2019-11-23 15:07:40,987 timer 6656 working
    [<_MainThread(MainThread, started 5332)>, <Timer(timer, started 6656)>]
    [<_MainThread(MainThread, started 5332)>]
    [<_MainThread(MainThread, started 5332)>]
    [<_MainThread(MainThread, started 5332)>]
    [<_MainThread(MainThread, started 5332)>]
    以上代码执行结果戳这里

      

    二.Lock

    1>.Lock的常用方法

    锁,一旦线程获得锁,其它试图获取锁的线程将被阻塞。
    
    锁:凡是存在资源共享争抢的地方都可以使用锁,从而只有一个使用者可以完全使用这个资源。
    
    锁常用的方法如下:
        acquire(blocking=True,timeout=-1):
        默认阻塞,阻塞可以设置超时事件。非阻塞时,timeout禁止设置。
        成功获取锁,返回True,否则返回False
    
        release():
        释放锁。可以从任何线程调用释放。
        已上锁的锁,会被重置为unlocked
        若在未上锁的锁上调用,则会抛出RuntimeError异常。

    2>.Lock锁使用案例

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 from threading import Thread,Lock
     7 import logging
     8 import time
     9 
    10 FORMAT = "%(asctime)s %(threadName)s %(thread)s %(message)s"
    11 logging.basicConfig(level=logging.INFO,format=FORMAT)
    12 
    13 cpus = []
    14 lock = Lock()
    15 
    16 def worker(count=10):
    17     logging.info("I'm working for U.")
    18     flag = False
    19     while True:
    20         lock.acquire()          #获取锁
    21         if len(cpus) >= count:
    22             flag = True
    23         time.sleep(0.0001)      #为了看出线程切换效果
    24         if not flag:
    25             cpus.append(1)
    26         lock.release()
    27         if flag:
    28             break
    29     logging.info("I finished . cups = {}".format(len(cpus)))
    30 
    31 
    32 for _ in range(10):
    33     Thread(target=worker,args=(1000,)).start()
    2019-11-23 16:03:35,225 Thread-1 16204 I'm working for U.
    2019-11-23 16:03:35,226 Thread-2 14436 I'm working for U.
    2019-11-23 16:03:35,226 Thread-3 1164 I'm working for U.
    2019-11-23 16:03:35,226 Thread-4 10460 I'm working for U.
    2019-11-23 16:03:35,227 Thread-5 5072 I'm working for U.
    2019-11-23 16:03:35,227 Thread-6 12016 I'm working for U.
    2019-11-23 16:03:35,227 Thread-7 9732 I'm working for U.
    2019-11-23 16:03:35,228 Thread-8 15644 I'm working for U.
    2019-11-23 16:03:35,228 Thread-9 104 I'm working for U.
    2019-11-23 16:03:35,228 Thread-10 16508 I'm working for U.
    2019-11-23 16:03:37,130 Thread-1 16204 I finished . cups = 1000
    2019-11-23 16:03:37,132 Thread-3 1164 I finished . cups = 1000
    2019-11-23 16:03:37,134 Thread-4 10460 I finished . cups = 1000
    2019-11-23 16:03:37,136 Thread-2 14436 I finished . cups = 1000
    2019-11-23 16:03:37,138 Thread-5 5072 I finished . cups = 1000
    2019-11-23 16:03:37,140 Thread-6 12016 I finished . cups = 1000
    2019-11-23 16:03:37,142 Thread-7 9732 I finished . cups = 1000
    2019-11-23 16:03:37,144 Thread-8 15644 I finished . cups = 1000
    2019-11-23 16:03:37,146 Thread-9 104 I finished . cups = 1000
    2019-11-23 16:03:37,148 Thread-10 16508 I finished . cups = 1000
    以上代码执行结果戳这里

    3>.加锁和解锁(计数器类案例)

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import threading
     7 from threading import Thread,Lock
     8 import logging
     9 import time
    10 
    11 FORMAT = "%(asctime)s %(threadName)s %(thread)s %(message)s"
    12 logging.basicConfig(level=logging.INFO,format=FORMAT)
    13 
    14 class Counter:
    15     def __init__(self):
    16         self._val = 0
    17         self.__lock = Lock()
    18 
    19     @property
    20     def value(self):
    21         with self.__lock:
    22             return self._val
    23 
    24     def inc(self):
    25         try:
    26             self.__lock.acquire()
    27             self._val += 1
    28         finally:
    29             self.__lock.release()
    30 
    31     def dec(self):
    32         with self.__lock:
    33             self._val -= 1
    34 
    35 
    36 def worker(c:Counter,count=100):
    37     for _ in  range(count):
    38         for i in range(-50,50):
    39             if i < 0:
    40                 c.dec()
    41             else:
    42                 c.inc()
    43 
    44 c = Counter()
    45 c1 = 10
    46 c2 = 10000
    47 
    48 for i in  range(c1):
    49     Thread(target=worker,args=(c,c2)).start()
    50 
    51 
    52 while True:
    53     time.sleep(1)
    54     print(threading.enumerate())
    55     if threading.active_count() == 1:
    56         print((c.value))
    57         break
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-6, started 8300)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-2, started 10732)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-4, started 2624)>, <Thread(Thread-5, started 1620)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>, <Thread(Thread-1, started 17728)>, <Thread(Thread-3, started 2680)>, <Thread(Thread-7, started 7532)>, <Thread(Thread-8, started 9480)>, <Thread(Thread-9, started 11044)>, <Thread(Thread-10, started 7164)>]
    [<_MainThread(MainThread, started 14856)>]
    0
    以上代码执行结果戳这里

    4>.锁的应用场景

    锁适用于访问和修改同一个共享资源的时候,即读写同一个资源的时候。
    
    如果全部都是读取同一个共享资源需要锁吗?   不需要。因为这时可以认为共享资源是不可变的,每一次读取它都是一样的值,所以不用加锁
    使用锁的注意事项: 少用锁,必要时用锁。使用了锁,多线程访问被锁的资源时,就成了串行,要么排队执行,要么争抢执行 举例,高速公路上车并行跑,可是到了省界只开放了一个收费口,过了这个口,车辆依然可以在多车道上一起跑。过收费口的时候,如果排队一辆辆过,加不加锁一样效率相当,但是一旦出现争抢,就必须加锁一辆辆过。注意,不管加不加锁,只要是一辆辆过,效率就下降了。 加锁时间越短越好,不需要就立即释放锁 一定要避免死锁
    不使用锁,有了效率,但是结果是错的。
    使用了锁,效率低下,但是结果是对的。
    所以,我们是为了效率要错误结果呢?还是为了对的结果,让计算机去计算吧。

    5>.非阻塞锁使用

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import threading
     7 import logging
     8 import time
     9 
    10 FORMAT = "%(asctime)s %(threadName)s %(thread)-10d %(message)s"
    11 logging.basicConfig(level=logging.INFO,format=FORMAT)
    12 
    13 lock = threading.Lock()
    14 
    15 def worker(l:threading.Lock):
    16     while True:
    17         flag = l.acquire(False)
    18         if flag:
    19             logging.info("do something.")       #为了显示效果,没有释放锁
    20         else:
    21             logging.info("try again")
    22             time.sleep(1)
    23 
    24 for i in range(5):
    25     threading.Thread(target=worker,name="worker={}".format(i),args=(lock,)).start()
    2019-11-24 15:58:31,932 worker=0 123145354420224 do something.
    2019-11-24 15:58:31,933 worker=0 123145354420224 try again
    2019-11-24 15:58:31,933 worker=1 123145359675392 try again
    2019-11-24 15:58:31,933 worker=2 123145364930560 try again
    2019-11-24 15:58:31,934 worker=3 123145370185728 try again
    2019-11-24 15:58:31,934 worker=4 123145375440896 try again
    2019-11-24 15:58:32,933 worker=0 123145354420224 try again
    2019-11-24 15:58:32,933 worker=1 123145359675392 try again
    2019-11-24 15:58:32,934 worker=2 123145364930560 try again
    2019-11-24 15:58:32,936 worker=4 123145375440896 try again
    2019-11-24 15:58:32,936 worker=3 123145370185728 try again
    2019-11-24 15:58:33,935 worker=0 123145354420224 try again
    2019-11-24 15:58:33,935 worker=1 123145359675392 try again
    2019-11-24 15:58:33,935 worker=2 123145364930560 try again
    2019-11-24 15:58:33,940 worker=4 123145375440896 try again
    2019-11-24 15:58:33,940 worker=3 123145370185728 try again
    2019-11-24 15:58:34,939 worker=0 123145354420224 try again
    2019-11-24 15:58:34,940 worker=1 123145359675392 try again
    2019-11-24 15:58:34,940 worker=2 123145364930560 try again
    2019-11-24 15:58:34,944 worker=4 123145375440896 try again
    2019-11-24 15:58:34,945 worker=3 123145370185728 try again
    2019-11-24 15:58:35,943 worker=1 123145359675392 try again
    2019-11-24 15:58:35,944 worker=0 123145354420224 try again
    2019-11-24 15:58:35,944 worker=2 123145364930560 try again
    2019-11-24 15:58:35,948 worker=4 123145375440896 try again
    2019-11-24 15:58:35,949 worker=3 123145370185728 try again
    ......
    以上代码执行结果戳这里

    三.可重入锁RLock 

    1>.可重入锁不可跨越线程

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import threading
     7 import time
     8 
     9 lock = threading.RLock()
    10 print(lock.acquire())                   #仅对当前线程上锁,但是代码并不会阻塞而是可以继续执行
    11 print(lock.acquire(blocking=True))
    12 print(lock.acquire(timeout=3))          #默认"blocking=True",因此可以设置值阻塞的超时时间,但当blocking=False时,timeout无法使用。
    13 print(lock.acquire(blocking=False))
    14 
    15 print("main thread {}".format(threading.main_thread().ident))
    16 print("lock in main thread {}".format(lock))
    17 
    18 print("{0} 我是分割线 {0}".format("*" * 15))
    19 
    20 lock.release()
    21 lock.release()
    22 lock.release()
    23 lock.release()
    24 # lock.release()                        #由于上面锁定的lock调用了4此锁定,因此解锁也只能是4次,若解锁次数超过上锁次数则抛出"RuntimeError: cannot release un-acquired lock"异常。
    25 
    26 print("main thread {}".format(threading.main_thread().ident))
    27 print("lock in main thread {}".format(lock))
    28 
    29 print("{0} 我是分割线 {0}".format("*" * 15))
    30 
    31 print(lock.acquire(blocking=False))
    32 print(lock.acquire(blocking=False))
    33 print("main thread {}".format(threading.main_thread().ident))
    34 print("lock in main thread {}".format(lock))
    35 
    36 # threading.Thread(target=lambda l:l.release(),args=(lock,)).start()          #可重入锁不可跨越线程,否则会抛出"RuntimeError: cannot release un-acquired lock"异常。
    37 lock.release()                                                            #可重入锁无论是上锁还是解锁要求在同一个线程中。
    38 
    39 time.sleep(3)
    40 print("main thread {}".format(threading.main_thread().ident))
    41 print("lock in main thread {}".format(lock))
    True
    True
    True
    True
    main thread 18096
    lock in main thread <locked _thread.RLock object owner=18096 count=4 at 0x00000172263B7C60>
    *************** 我是分割线 ***************
    main thread 18096
    lock in main thread <unlocked _thread.RLock object owner=0 count=0 at 0x00000172263B7C60>
    *************** 我是分割线 ***************
    True
    True
    main thread 18096
    lock in main thread <locked _thread.RLock object owner=18096 count=2 at 0x00000172263B7C60>
    main thread 18096
    lock in main thread <locked _thread.RLock object owner=18096 count=1 at 0x00000172263B7C60>
    以上代码执行结果戳这里

    2>.为另一个线程传入同一个RLock对象

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import threading
     7 import time
     8 
     9 lock = threading.RLock()
    10 
    11 def sub(l:threading.RLock):
    12     print("{}:{}".format(threading.current_thread(),l.acquire()))           #阻塞
    13     print("{}:{}".format(threading.current_thread(),l.acquire()))
    14     print("lock in sub thread {}".format(lock))
    15     l.release()
    16     print("release in sub 1")
    17     print("lock in sub thread {}".format(lock))
    18     l.release()
    19     print("release in sub 2")
    20     print("lock in sub thread {}".format(lock))
    21 
    22 
    23 print(lock.acquire())
    24 print("main thread {}".format(threading.main_thread().ident))
    25 print("lock in main thread {}".format(lock))
    26 
    27 print("{0} 我是分割线 {0}".format("*" * 15))
    28 
    29 threading.Timer(2,sub,(lock,)).start()          #为另一个线程传入同一个lock对象
    30 
    31 print("in main thread, {}".format(lock.acquire()))
    32 lock.release()
    33 time.sleep(5)
    34 print("release lock in main thread  =======",end="
    
    ")
    35 lock.release()
    36 print("lock in main thread {}".format(lock))
    True
    main thread 2456
    lock in main thread <locked _thread.RLock object owner=2456 count=1 at 0x000001BF29077B10>
    *************** 我是分割线 ***************
    in main thread, True
    release lock in main thread  =======
    
    lock in main thread <unlocked _thread.RLock object owner=0 count=0 at 0x000001BF29077B10>
    <Timer(Thread-1, started 9072)>:True
    <Timer(Thread-1, started 9072)>:True
    lock in sub thread <locked _thread.RLock object owner=9072 count=2 at 0x000001BF29077B10>
    release in sub 1
    lock in sub thread <locked _thread.RLock object owner=9072 count=1 at 0x000001BF29077B10>
    release in sub 2
    lock in sub thread <unlocked _thread.RLock object owner=0 count=0 at 0x000001BF29077B10>
    以上代码执行结果戳这里

    3>.可重入锁相关总结

      可重入锁,是线程相关的锁。可在同一个线程中获取锁,并可以继续在同一线程不阻塞多次获取锁。

      当锁未释放完,其它线程获取锁就会阻塞,直到当前持有锁的线程释放完锁。
      锁都应该使用完后释放。可重入锁也是锁,应该acquire多少次,就release多少次。
      

    四.Condition

    1>.Condition常用方法

    Condition(lock=None):
      可传入一个Lock或者RLock对象,默认是RLock。

    acquire(*args):
      获取锁。

    wait(self,timeout=None):
      等待或超时。

    notify(n=1):
      唤醒至多指定数目个数的等待的线程,没有等待的线程就没有任何操作。

    notify_all():
      唤醒所有等待的线程。

    2>.生产者消费者模型

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 from threading import Event,Thread,Condition
     8 import time
     9 import random
    10 
    11 FORMAT = "%(asctime)s %(threadName)s %(thread)s %(message)s"
    12 logging.basicConfig(format=FORMAT,level=logging.INFO)
    13 
    14 class Dispachter:
    15     def __init__(self):
    16         self.data = None
    17         self.event = Event()                #event只是为了使用方便,与逻辑无关
    18         self.cond =Condition()
    19 
    20     def produce(self,total):
    21         for _ in range(total):
    22             data = random.randint(1,100)
    23             with self.cond:
    24                 logging.info(data)
    25                 self.data = data
    26                 # self.cond.notify_all()
    27                 self.cond.notify(2)
    28             self.event.wait(1)
    29 
    30     def consume(self):
    31         while not self.event.is_set():
    32             with self.cond:
    33                 self.cond.wait()
    34                 data = self.data
    35                 logging.info("recieved {}".format(data))
    36                 self.data = None
    37             self.event.wait(0.5)
    38 
    39 d = Dispachter()
    40 p = Thread(target=d.produce,name="producer",args=(10,))
    41 
    42 #增加消费者
    43 for i in  range(5):
    44     c = Thread(target=d.consume,name="consumer")
    45     c.start()
    46 
    47 p.start()
    2019-11-25 22:24:45,076 producer 12228 64
    2019-11-25 22:24:45,076 consumer 7612 recieved 64
    2019-11-25 22:24:45,076 consumer 18400 recieved None
    2019-11-25 22:24:46,077 producer 12228 41
    2019-11-25 22:24:46,077 consumer 15008 recieved 41
    2019-11-25 22:24:46,078 consumer 16440 recieved None
    2019-11-25 22:24:47,077 producer 12228 98
    2019-11-25 22:24:47,077 consumer 14832 recieved 98
    2019-11-25 22:24:47,077 consumer 7612 recieved None
    2019-11-25 22:24:48,077 producer 12228 39
    2019-11-25 22:24:48,077 consumer 18400 recieved 39
    2019-11-25 22:24:48,078 consumer 15008 recieved None
    2019-11-25 22:24:49,078 producer 12228 79
    2019-11-25 22:24:49,078 consumer 16440 recieved 79
    2019-11-25 22:24:49,078 consumer 14832 recieved None
    2019-11-25 22:24:50,079 producer 12228 39
    2019-11-25 22:24:50,079 consumer 7612 recieved 39
    2019-11-25 22:24:50,080 consumer 15008 recieved None
    ......
    以上代码执行结果戳这里

    3>.Condition总结

      Condition用于生产者消费者模型中,解决生产者消费者速度匹配的问题。
    
      采用了通知机制,非常有效率。
      使用方式:
        使用Condition,必须先acquire,用完了要release,因为内部使用了锁,默认使用RLock,最好的方式是使用with上下文。
        消费者这wait,等待通知。
        生产者生产好消息,对消费者发通知,可以使用notify或者notify_all方法。

    五.semaphore

    1>.semaphore常用方法 

      和Lock很像,信号量对象内部维护一个倒计数器,每一次acquire都会减1,当acquire方法发现计数为0就阻塞请求的线程,直到其它线程对信号量release后,计数大于0,恢复阻塞的线程。换句话说,计数器永远不会低于0,因为acquire的时候,发现是0,都会被阻塞。
    
      semaphore常用方法如下:     Semaphore(value
    =1):       构造方法。value小于0,抛ValueError异常     acquire(blocking=True, timeout=None):       获取信号量,计数器减1,获取成功返回True     release():       释放信号量,计数器加1

    2>.基本使用案例(存在release方法超界限的问题) 

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 
     7 from threading import Thread, Semaphore
     8 import logging
     9 import time
    10 
    11 FORMAT = '%(asctime)s %(threadName)-12s %(thread)-8s %(message)s'
    12 logging.basicConfig(format=FORMAT, level=logging.INFO)
    13 
    14 def worker(s:Semaphore):
    15     logging.info("in worker thread")
    16     logging.info(s.acquire())
    17     logging.info('worker thread over')
    18 
    19 
    20 # 定义信号量的个数为3
    21 s = Semaphore(3)
    22 print(s.__dict__)
    23 
    24 logging.info(s.acquire())       #获取一把锁之后,"_value"计数器就会减1。
    25 
    26 
    27 print(s.acquire(),s._value)
    28 
    29 print(s.acquire(),s._value)
    30 
    31 Thread(target=worker, name="worker",args=(s,)).start()
    32 time.sleep(2)
    33 logging.info(s.acquire(False))
    34 logging.info(s.acquire(timeout=3))
    35 
    36 # 释放一个
    37 logging.info('release one')
    38 s.release()
    39 print(s.__dict__)           #释放锁后可以被"worker"线程获取
    40 
    41 s.release()
    42 s.release()
    43 s.release()
    44 s.release()
    45 s.release()                 #此处我们可以故意多释放几次锁
    46 
    47 print(s.__dict__)           #竟然内置计数器"_value"达到了6(也有可能是5,因为worker线程中需要获取一把锁),这样实际上超出我们的最大值,需要解决这个问题。
    2019-11-26 09:54:22,345 MainThread   140735817298880 True
    2019-11-26 09:54:22,345 worker       123145401769984 in worker thread
    {'_cond': <Condition(<unlocked _thread.lock object at 0x102929170>, 0)>, '_value': 3}
    True 1
    True 0
    2019-11-26 09:54:24,346 MainThread   140735817298880 False
    2019-11-26 09:54:27,349 MainThread   140735817298880 False
    2019-11-26 09:54:27,349 MainThread   140735817298880 release one
    {'_cond': <Condition(<unlocked _thread.lock object at 0x102929170>, 0)>, '_value': 1}
    {'_cond': <Condition(<unlocked _thread.lock object at 0x102929170>, 0)>, '_value': 6}
    2019-11-26 09:54:27,350 worker       123145401769984 True
    2019-11-26 09:54:27,350 worker       123145401769984 worker thread over
    以上代码执行结果戳这里

    3>.BoundedSemaphore类(有边界的信号量,不允许使用release超出初始化范围,否则,抛出“ValueError: Semaphore released too many times”异常)

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 
     7 from threading import Thread, BoundedSemaphore
     8 import logging
     9 import time
    10 
    11 FORMAT = '%(asctime)s %(threadName)-12s %(thread)-8s %(message)s'
    12 logging.basicConfig(format=FORMAT, level=logging.INFO)
    13 
    14 def worker(s:BoundedSemaphore):
    15     logging.info("in worker thread")
    16     logging.info(s.acquire())
    17     logging.info('worker thread over')
    18 
    19 
    20 # 定义有边界信号量的个数为3
    21 s = BoundedSemaphore(3)
    22 print(s.__dict__)
    23 
    24 logging.info(s.acquire())       #获取一把锁之后,"_value"计数器就会减1。
    25 
    26 
    27 print(s.acquire(),s._value)
    28 
    29 print(s.acquire(),s._value)
    30 
    31 Thread(target=worker, name="worker",args=(s,)).start()
    32 time.sleep(2)
    33 logging.info(s.acquire(False))
    34 logging.info(s.acquire(timeout=3))
    35 
    36 # 释放一个
    37 logging.info('release one')
    38 s.release()
    39 print(s.__dict__)           #释放锁后可以被"worker"线程获取
    40 
    41 s.release()
    42 s.release()
    43 s.release()
    44 s.release()
    45 s.release()                 #此处我们可以故意多释放几次锁,一旦release超出初始值的范围就抛出异常!
    46 
    47 print(s.__dict__)          
    {'_cond': <Condition(<unlocked _thread.lock object at 0x102029170>, 0)>, '_value': 3, '_initial_value': 3}
    True 1
    True 0
    2019-11-26 10:09:17,632 MainThread   140735817298880 True
    2019-11-26 10:09:17,635 worker       123145507561472 in worker thread
    2019-11-26 10:09:19,638 MainThread   140735817298880 False
    {'_cond': <Condition(<unlocked _thread.lock object at 0x102029170>, 0)>, '_value': 1, '_initial_value': 3}
    2019-11-26 10:09:22,643 MainThread   140735817298880 False
    2019-11-26 10:09:22,644 MainThread   140735817298880 release one
    Traceback (most recent call last):
      File "/yinzhengjie/python/devops/python基础/09.线程/04.信号量.py", line 43, in <module>
    2019-11-26 10:09:22,644 worker       123145507561472 True
    2019-11-26 10:09:22,644 worker       123145507561472 worker thread over
        s.release()
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 483, in release
        raise ValueError("Semaphore released too many times")
    ValueError: Semaphore released too many times
    以上代码执行结果戳这里

    4>.应用举例(一个简单的连接池)

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import random
     7 import threading
     8 import logging
     9 import time
    10 
    11 FORMAT = '%(asctime)s %(threadName)s %(thread)-8d %(message)s'
    12 logging.basicConfig(level=logging.INFO, format=FORMAT)
    13 
    14 class Conn:
    15     def __init__(self, name):
    16         self.name = name
    17 
    18 """
    19 连接池
    20     因为资源有限,且开启一个连接成本高,所以,使用连接池。
    21 
    22 一个简单的连接池
    23     连接池应该有容量(总数),有一个工厂方法可以获取连接,能够把不用的连接返回,供其他调用者使用。
    24 
    25 使用信号量解决资源有限的问题。 
    26     如果池中有资源,请求者获取资源时信号量减1,拿走资源。当请求超过资源数,请求者只能等待。当使用者用完归还资源后信号量加1,等待线程就可以被唤醒拿走资源。 
    27     注意:这个连接池的例子不能用到生成环境,只是为了说明信号量使用的例子,连接池还有很多未完成功能。
    28 """
    29 class Pool:
    30     def __init__(self, count:int):
    31         self.count = count
    32         #池中提前放着连接备用
    33         self.pool = [self._connect('conn-{}'.format(i)) for i in range(self.count)]
    34         self.semaphore = threading.Semaphore(self.count)
    35 
    36     def _connect(self, conn_name):
    37         # 创建连接的方法,返回一个连接对象
    38         return Conn(conn_name)
    39 
    40     def get_conn(self):
    41         #从池中拿走一个连接
    42         logging.info('get~~~~~~~~~~~~~')
    43         self.semaphore.acquire()
    44         logging.info('-------------------------')
    45         return self.pool.pop()
    46 
    47     def return_conn(self, conn: Conn):
    48         # 向池中返回一个连接对象
    49         logging.info('return~~~~~~~~~~~~~')
    50         self.pool.append(conn)
    51         self.semaphore.release()
    52 
    53 def worker(pool:Pool):
    54     conn = pool.get_conn()
    55     logging.info(conn)
    56     # 模拟使用了一段时间
    57     time.sleep(random.randint(1, 5))
    58     pool.return_conn(conn)
    59 
    60 # 初始化连接池
    61 pool = Pool(3)
    62 
    63 for i in range(6):
    64     threading.Thread(target=worker, name='worker-{}'.format(i), args=(pool,)).start()
    2019-11-26 11:27:58,148 worker-0 123145324670976 get~~~~~~~~~~~~~
    2019-11-26 11:27:58,148 worker-0 123145324670976 -------------------------
    2019-11-26 11:27:58,148 worker-0 123145324670976 <__main__.Conn object at 0x102db0438>
    2019-11-26 11:27:58,149 worker-1 123145329926144 get~~~~~~~~~~~~~
    2019-11-26 11:27:58,149 worker-1 123145329926144 -------------------------
    2019-11-26 11:27:58,149 worker-1 123145329926144 <__main__.Conn object at 0x102db03c8>
    2019-11-26 11:27:58,149 worker-2 123145335181312 get~~~~~~~~~~~~~
    2019-11-26 11:27:58,149 worker-2 123145335181312 -------------------------
    2019-11-26 11:27:58,150 worker-2 123145335181312 <__main__.Conn object at 0x102db0240>
    2019-11-26 11:27:58,150 worker-3 123145340436480 get~~~~~~~~~~~~~
    2019-11-26 11:27:58,150 worker-4 123145345691648 get~~~~~~~~~~~~~
    2019-11-26 11:27:58,151 worker-5 123145350946816 get~~~~~~~~~~~~~
    2019-11-26 11:28:02,153 worker-0 123145324670976 return~~~~~~~~~~~~~
    2019-11-26 11:28:02,153 worker-3 123145340436480 -------------------------
    2019-11-26 11:28:02,154 worker-3 123145340436480 <__main__.Conn object at 0x102db0438>
    2019-11-26 11:28:02,154 worker-1 123145329926144 return~~~~~~~~~~~~~
    2019-11-26 11:28:02,154 worker-4 123145345691648 -------------------------
    2019-11-26 11:28:02,154 worker-4 123145345691648 <__main__.Conn object at 0x102db03c8>
    2019-11-26 11:28:03,154 worker-2 123145335181312 return~~~~~~~~~~~~~
    2019-11-26 11:28:03,155 worker-5 123145350946816 -------------------------
    2019-11-26 11:28:03,155 worker-5 123145350946816 <__main__.Conn object at 0x102db0240>
    2019-11-26 11:28:05,155 worker-4 123145345691648 return~~~~~~~~~~~~~
    2019-11-26 11:28:07,154 worker-3 123145340436480 return~~~~~~~~~~~~~
    2019-11-26 11:28:08,159 worker-5 123145350946816 return~~~~~~~~~~~~~
    以上代码执行结果戳这里

    5>.信号量和锁

    信号量:
      可以多个线程访问共享资源,但这个共享资源数量有限。

    锁:
      可以看做特殊的信号量,即信号量计数器初值为1。只允许同一个时间一个线程独占资源。

      

    六.Queue的线程安全

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import queue
     7 
     8 
     9 """
    10 标准库queue模块,提供FIFO的Queue、LIFO的队列、优先队列。
    11 
    12 Queue类是线程安全的,适用于多线程间安全的交换数据。内部使用了Lock和Condition。
    13 
    14 为什么讲魔术方法时,说实现容器的大小,不准确? 
    15     1>.如果不加锁,是不可能获得准确的大小的,因为你刚读取到了一个大小,还没有取走数据,就有可能被其他线程改了。 
    16     2>.Queue类的size虽然加了锁,但是,依然不能保证立即get、put就能成功,因为读取大小和get、put方法是分开的。
    17 """
    18 
    19 q = queue.Queue(8)
    20 
    21 if q.qsize() == 7:
    22     q.put("abc")    #上下两句可能被打断
    23 
    24 if q.qsize() == 1:
    25     q.get()         #未必会成功
  • 相关阅读:
    截图、贴图神器——Snipaste
    MySQL (InnoDB)在什么情况下无法使用索引
    美化博客园样式
    《快速阅读》全书脉络梳理
    MySQL 配置统计数据
    使用 MWeb + Typora 写作并发布到博客园
    浅谈操作系统的用户态和内核态
    一个后端工程师的开发软件
    程序写日志文件时该不该加锁 & PHP 写日志为什么加锁
    《小岛经济学》读书笔记
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/11886778.html
Copyright © 2011-2022 走看看