Skip to main content
 首页 » 编程设计

python之Python 中的多线程

2025年01月19日31xiaohuochai

我在 python 中实现多线程时遇到了一些问题。这个问题非常针对我的用例。在浏览了很多相同的帖子后,我部署了最广泛推荐/使用的方法。

我首先按如下方式定义我的线程类。

class myThread(Thread): 
    def __init__(self, graphobj, q): 
        Thread.__init__(self) 
        self.graphobj = graphobj 
        self.q = q 
    def run(self): 
        improcess(self.graphobj, self.q) 

发布我定义的函数来完成所有需要的处理。

def improcess(graphobj, q): 
    while not exitFlag: 
        queueLock.acquire() 
        if not q.empty(): 
            photo_id = q.get() 
            queueLock.release() 
            # Complete processing 
        else: 
            queueLock.release() 

现在是我卡住的部分。我能够完全按原样运行下面提到的代码,没有任何问题。但是,如果我尝试将其包装在一个函数中,它就会崩溃。

def train_control(graphobj, photo_ids): 
    workQueue = Queue(len(photo_ids)) 
    for i in range(1,5): 
        thread = myThread(graphobj=graphobj, q=workQueue) 
        thread.start() 
        threads.append(thread) 
    queueLock.acquire() 
    for photo_id in photo_ids: 
        workQueue.put(photo_id) 
    queueLock.release() 
    while not workQueue.empty(): 
        pass 
    exitFlag = 1 
    for t in threads: 
        t.join() 

我所说的中断是指线程完成了它们的工作,但它们不会停止等待,即 exitFlag 永远不会设置为 1。我不确定如何进行这项工作。

不幸的是,我们的系统设计是这样的,这段代码需要包装在一个可以被另一个模块调用的函数中,所以把它拉出来并不是一个真正的选择。

期待听取专家的意见。提前致谢。

编辑:忘记在初稿中提及这一点。我全局初始化 exitFlag 并将其值设置为 0。

下面是我为解决这个问题而创建的最小的、可验证的代码片段:

import threading 
import Queue 
 
globvar01 = 5 
globvar02 = 7 
exitFlag = 0 
 
globlist = [] 
threads = [] 
 
queueLock = threading.Lock() 
workQueue = Queue.Queue(16) 
 
class myThread(threading.Thread): 
    def __init__(self, threadID, q): 
        threading.Thread.__init__(self) 
        self.threadID = threadID 
        self.q = q 
    def run(self): 
        print "Starting thread " + str(self.threadID) 
        myfunc(self.threadID, self.q) 
        print "Exiting thread " + str(self.threadID) 
 
def myfunc(threadID, q): 
    while not exitFlag: 
        queueLock.acquire() 
        if not workQueue.empty(): 
            thoughtnum = q.get() 
            queueLock.release() 
            print "Processing thread " + str(threadID) 
            if (thoughtnum < globvar01): 
                globlist.append([1,2,3]) 
            elif (thoughtnum < globvar02): 
                globlist.append([2,3,4]) 
        else: 
            queueLock.release() 
 
def controlfunc(): 
    for i in range(1,5): 
        thread = myThread(i, workQueue) 
        thread.start() 
        threads.append(thread) 
    queueLock.acquire() 
    for i in range(1,11): 
        workQueue.put(i) 
    queueLock.release() 
    # Wait for queue to empty 
    while not workQueue.empty(): 
        pass 
    exitFlag = 1 
    # Wait for all threads to complete 
    for t in threads: 
        t.join() 
 
print "Starting main thread" 
 
controlfunc() 
 
print "Exiting Main Thread" 

请您参考如下方法:

在您的 MCVE 中,唯一缺少的是:

while not workQueue.empty(): 
    pass 
global exitFlag  # Need this or `exitFlag` is a local variable only. 
exitFlag = 1 

但是,您可以通过使用队列中的标记值来关闭工作线程来消除队列锁和退出标志,从而消除自旋等待。工作线程将在 q.get() 上休眠,主线程将不必自旋等待空队列:

#!python2 
from __future__ import print_function 
import threading 
import Queue 
 
debug = 1 
console = threading.Lock() 
 
def tprint(*args,**kwargs): 
    if debug: 
        name = threading.current_thread().getName() 
        with console: 
            print('{}: '.format(name),end='') 
            print(*args,**kwargs) 
 
globvar01 = 5 
globvar02 = 7 
 
globlist = [] 
threads = [] 
 
workQueue = Queue.Queue(16) 
 
class myThread(threading.Thread): 
    def __init__(self, threadID, q): 
        threading.Thread.__init__(self) 
        self.threadID = threadID 
        self.q = q 
    def run(self): 
        tprint("Starting thread " + str(self.threadID)) 
        myfunc(self.threadID, self.q) 
        tprint("Exiting thread " + str(self.threadID)) 
 
def myfunc(threadID, q): 
    while True: 
        thoughtnum = q.get() 
        tprint("Processing thread " + str(threadID)) 
        if thoughtnum is None: 
            break 
        elif thoughtnum < globvar01: 
            globlist.append([1,2,3]) 
        elif thoughtnum < globvar02: 
            globlist.append([2,3,4]) 
 
def controlfunc(): 
    for i in range(1,5): 
        thread = myThread(i, workQueue) 
        thread.start() 
        threads.append(thread) 
    for i in range(1,11): 
        workQueue.put(i) 
    # Wait for all threads to complete 
    for t in threads: 
        workQueue.put(None) 
    for t in threads: 
        t.join() 
 
tprint("Starting main thread") 
 
controlfunc() 
 
tprint("Exiting Main Thread") 

输出:

MainThread: Starting main thread 
Thread-1: Starting thread 1 
Thread-2: Starting thread 2 
Thread-3: Starting thread 3 
Thread-4: Starting thread 4 
Thread-1: Processing thread 1 
Thread-2: Processing thread 2 
Thread-3: Processing thread 3 
Thread-4: Processing thread 4 
Thread-1: Processing thread 1 
Thread-2: Processing thread 2 
Thread-3: Processing thread 3 
Thread-4: Processing thread 4 
Thread-1: Processing thread 1 
Thread-2: Processing thread 2 
Thread-3: Processing thread 3 
Thread-4: Processing thread 4 
Thread-1: Processing thread 1 
Thread-2: Processing thread 2 
Thread-3: Exiting thread 3 
Thread-4: Exiting thread 4 
Thread-1: Exiting thread 1 
Thread-2: Exiting thread 2 
MainThread: Exiting Main Thread