你好呀~

线程优先级队列实现线程间同步

一. 本篇目的

  本篇旨在介绍使用队列实现线程之间的同步,我们知道程序界的同步和异步的概念和生活中是反着的,在代码中,同步指的是有顺序进行,异步指的是同时进行。线程作为异步的方式之一,在各项目中应用广泛,那么在异步的线程之间如何实现同步呢?

  不太好理解,没关系。我讲个故事吧:为了去大荒夺得某些宝物,本座同时派出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会卡死。

 

posted @ 2021-11-13 12:40  测神  阅读(80)  评论(0编辑  收藏  举报