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="\n\n") 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() #未必会成功
本文来自博客园,作者:尹正杰,转载请注明原文链接:https://www.cnblogs.com/yinzhengjie/p/11886778.html,个人微信: "JasonYin2020"(添加时请备注来源及意图备注,有偿付费)
当你的才华还撑不起你的野心的时候,你就应该静下心来学习。当你的能力还驾驭不了你的目标的时候,你就应该沉下心来历练。问问自己,想要怎样的人生。