线程优先级队列实现线程间同步
一. 本篇目的
本篇旨在介绍使用队列实现线程之间的同步,我们知道程序界的同步和异步的概念和生活中是反着的,在代码中,同步指的是有顺序进行,异步指的是同时进行。线程作为异步的方式之一,在各项目中应用广泛,那么在异步的线程之间如何实现同步呢?
不太好理解,没关系。我讲个故事吧:为了去大荒夺得某些宝物,本座同时派出100名部下前往大荒(一次开多个线程-异步),但本座提前有交代,要先夺清灵涎,再夺血矛,再夺异火,顺序不可打乱(任务要有顺序-同步),然后手下便去完成去了。
线程异步配合任务队列同步,便是本篇要讲的。
二. 概念解释
线程
- run():用以表示线程活动的方法。
- start():启动线程活动。
- join():这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
- lock():lock使用acquire时,为加锁,会让run方法挂着,直到release解锁才同时执行。
队列
- qsize() :返回队列的大小。
- empty() 如果队列为空,返回True,反之False。
- get():读队列。
- put():写队列。
三. 案例展示
import queue import threading # 5. 创建线程 class MyThread(threading.Thread): def __init__(self, thread_id, name, q): threading.Thread.__init__(self) self.thread_id = thread_id self.name = name self.q = q def run(self): print("启动 " + self.name) self.process_data(self.name, self.q) print("退出 " + self.name) @staticmethod def process_data(thread_name, qn): """ 体现 线程优先级队列,队列实现线程间的同步(有顺序) """ while not exitFlag: # 正是因为线程的特性,退出死循环的标志为外面的队列。 threadLock.acquire() if not workQueue.empty(): data = qn.get() threadLock.release() print("%s执行任务-%s" % (thread_name, data)) else: threadLock.release() """ # 可以直接简化为下面的,因为已经锁过一次了,上面的忽悠人可行。 if not workQueue.empty(): data = qn.get() print("%s执行任务-%s" % (thread_name, data)) """ # 1. 定义线程、任务、队列 exitFlag = 0 # 退出线程标志 threadList = ["线程1", "线程2", "线程3"] nameList = ["任务1", "任务2", "任务3", "任务4", "任务5"] threadLock = threading.Lock() # 锁住 workQueue = queue.Queue(10) # 空队列,加的任务是nameList里的东西,实际业务中加的是任务对象 threads = [] # 装线程对象 _id = 1 # 用来标识第几个线程 # 2. 挂起(启动但未运行)多个线程 for tName in threadList: thread = MyThread(_id, tName, workQueue) thread.start() # 启动线程活动。 threads.append(thread) _id += 1 # 3. 锁住-队列里加上任务(这里是字符串),-释放锁 # threadLock.acquire() for word in nameList: workQueue.put(word) # threadLock.release() # 释放了锁就在执行任务 # 4. 判断是否执行完了任务,等待执行完 while not workQueue.empty(): pass # 通知线程是时候退出 exitFlag = 1 for t in threads: # 等待所有线程完成 t.join() # 等待至线程中止。 print("退出主线程")
"""
前面的启动的123是因为在循环里肯定是顺序的;中间的的执行顺序以队列任务排序为准,哪个线程抢到就归谁;退出时顺序取决于哪个线程先执行完。
"""
四. Lock和Rlock区别?
1. 一个lock被释放前不能被其他线程获得acquire;一个Rlock可以被其他任意线程获得。
2. 一个lock可以被其他线程释放;Rlock只能被获得他的线程释放。
3. lock被一个线程占有;Rlock可以被其他线程获得。
4. lock的运行速度快;运行速度比lock慢。
5. 同一线程内,对RLock
进行多次acquire()
操作,程序不会阻塞,而Lock会卡死。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架