Python中的多线程

时间:2017-11-02 18:53:02

标签: python multithreading python-2.7 queue multiprocessing

我在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"

2 个答案:

答案 0 :(得分:1)

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

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

但是,您可以通过使用队列中的sentinel值来关闭工作线程来消除queueLock和exitFlag,并消除了等待旋转。工作线程将在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

答案 1 :(得分:0)

您需要确保exitFlag在产生任何线程之前设置为0(False),否则impprocess()他们不会做任何事情并且队列将保持非空。

如果您将exitFlag作为全局并且未在之前的运行中清除,则可能会发生此问题。