目录
上例中,程序本身不是线程安全的,程序逻辑有很多瑕疵,但是可以很好的帮助理解Condition的使用,和生产消费者模型
线程同步
概念:
- 线程同步,线程间协同,通过某种技术,让一个线程访问某些数据时,其他线程不能访问这些数据,直到该线程完成对数据的操作
- 不同的操作系统实现的技术有所不同,有临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、时间Even等
Event
Event时间,是线程间通信机制中最简单的实现,使用一个内部的标记Flag, 通过Flag的True或False的变化来进行操作
名称 含义 set() 标记设置为True clear() 标记设置为False is_set() 标记是否为True wait(timeout = None) 设置等待标记为True的时长,None为无限等待。等到返回Ture,未等到超时返回False 需求:老板雇佣了一个工人,让他生产被子,老板一直等待这个工人,直到生产了10个杯子
from threading import Event ,Thread import logging import time FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s" logging.basicConfig(format=FORMAT,level=logging.INFO) def boss(event:Event): logging.info("I m boss, waiting for U.") #等待 event.wait() logging.info("Good job") def worker(event:Event,count=10): logging.info("I m working for U.") cups = [] while True: logging.info("make 1") time.sleep(0.5) cups.append(1) if len(cups) >=10: #通知 event.set() break logging.info("I finished my job. cups={} ".format(cups)) event = Event() w = Thread(target=worker,args=(event,)) b = Thread(target=boss,args=(event,)) b.start() w.start() #结果: 2021-06-05 21:10:15,208 Thread-2 15120 I m boss, waiting for U. 2021-06-05 21:10:15,209 Thread-1 49616 I m working for U. 2021-06-05 21:10:15,209 Thread-1 49616 make 1 2021-06-05 21:10:15,722 Thread-1 49616 make 1 2021-06-05 21:10:16,228 Thread-1 49616 make 1 2021-06-05 21:10:16,734 Thread-1 49616 make 1 2021-06-05 21:10:17,243 Thread-1 49616 make 1 2021-06-05 21:10:17,746 Thread-1 49616 make 1 2021-06-05 21:10:18,251 Thread-1 49616 make 1 2021-06-05 21:10:18,756 Thread-1 49616 make 1 2021-06-05 21:10:19,257 Thread-1 49616 make 1 2021-06-05 21:10:19,764 Thread-1 49616 make 1 2021-06-05 21:10:20,268 Thread-1 49616 I finished my job. cups=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 2021-06-05 21:10:20,268 Thread-2 15120 Good job
总结:
- 使用同一个Event对象的标记Flag
- 谁wait就是等到Flag变为True,或等到超时返回False。不限制等待的个数
wait使用
- Event的wait优先于time.sleep,他会更快的切换到其他的线程,提高并发效率
from threading import Event ,Thread import logging import time logging.basicConfig(level=logging.INFO) def do(event:Event,interval:int): while not event.wait(interval): #条件中返回True或者False logging.info("do sth") e = Event() Thread(target=do,args=(e,3)).start() e.wait(10) #也可以使用time.sleep(10) e.set() print("main exit") 结果: INFO:root:do sth INFO:root:do sth INFO:root:do sth main exit
Event练习
实现Timer,延时执行线程,延时计算add(x,y)
思路:Timer的构造函数中参数得有哪些?如何实现start启动一个线程执行函数?如何cancel取消待执行任务?
思路实现
from threading import Event,Thread import datetime import logging logging.basicConfig(level=logging.INFO) def add(x:int,y:int): logging.info(x + y) class Timer: def __init__(self,interval,fn,*args,**kwargs): self.interval = interval self.fn = fn self.args =args self.kwargs = kwargs self.event = Event() def start(self): Thread(target=self._run).start() def cancel(self): self.event.set() def _run(self): start_time = datetime.datetime.now() logging.info("watting") self.event.wait(self.interval) logging.info(self.event.is_set()) if not self.event.is_set(): #也可以:if not self.event.wait(self.interval) self.fn(*self.args,**self.kwargs) delta = (datetime.datetime.now() - start_time).total_seconds() logging.info("finished {} ".format(delta) ) self.event.set() t = Timer(10,add,4,50) t.start() e = Event() e.wait(4) print("Main Process") 结果: INFO:root:watting Main Process INFO:root:False INFO:root:54 INFO:root:finished 10.000212
Lock:锁机制
锁,凡是存在共享资源争抢的地方都可以使用锁,从而保证只有一个使用者可以完全按使用这个资源
名称 含义 acquire(blocking = True, timeout=-1) 默认阻塞,阻塞可以设置超时时间。非阻塞时,timeout禁止设置。成功获取锁,返回True,否者返回False release() 释放锁。可以从任何线程调用释放。已上锁的锁,会被重置为unlock,未上锁的锁上调用,抛出RuntimeError异常 需求:订单生产1000个杯子,阻止10个人生产 【无锁版本】
from threading import Event,Thread import time import threading import logging FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s' logging.basicConfig(format=FORMAT,level=logging.INFO) cups =[] def worker(count =10): logging.info("I`m workinf for U") while len(cups) < count: time.sleep(0.00000001) cups.append(1) logging.info("I`m finished cups = {}".format(len(cups))) for _ in range(10): Thread(target=worker,args=(100,)).start() 结果: 2021-06-13 10:19:56,488 Thread-7 644 I`m workinf for U 2021-06-13 10:19:56,488 Thread-8 18800 I`m workinf for U 2021-06-13 10:19:56,488 Thread-9 17828 I`m workinf for U 2021-06-13 10:19:56,488 Thread-10 20444 I`m workinf for U 2021-06-13 10:19:56,633 Thread-3 7056 I`