python - 全局变量

0 投票
3 回答
694 浏览
提问于 2025-04-18 12:01

我找到了一份关于Python中队列和线程的教程。这里是代码:

#!/usr/bin/python

import Queue
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print "Starting " + self.name
        process_data(self.name, self.q)
        print "Exiting " + self.name

def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %s" % (threadName, data)
            time.sleep(3)
            print "%s finished processing %s" % (threadName, data)
        else:
            queueLock.release()
        time.sleep(1)


threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1

# Create new threads
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1


# Fill the queue
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()

# Wait for queue to empty
while not workQueue.empty():
    pass

# Notify threads it's time to exit
exitFlag = 1

# Wait for all threads to complete
for t in threads:
    t.join()
print "Exiting Main Thread"

我对Python和线程+队列非常陌生,请多多包涵。

我打算写几个线程类(比如:myThread1、myThread2等等)。在main()函数中,它会接收命令行参数,然后决定创建哪个线程类。

所以我在考虑把myThread类和main分成一个单独的Python文件。同时,我也想把process_data方法移到myThread类中,以便为每个线程类执行一套不同的规则。可以把这理解为封装。

这是我尝试过的:

mythread.py:

#!/usr/bin/python

import Queue
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print "Starting " + self.name
        process_data(self.name, self.q)
        print "Exiting " + self.name

def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %s" % (threadName, data)
            time.sleep(3)
            print "%s finished processing %s" % (threadName, data)
        else:
            queueLock.release()
        time.sleep(1)

main.py

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1

# Create new threads
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1


# Fill the queue
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()

# Wait for queue to empty
while not workQueue.empty():
    pass

# Notify threads it's time to exit
exitFlag = 1

# Wait for all threads to complete
for t in threads:
    t.join()
print "Exiting Main Thread"

现在我遇到了一些问题:

  1. 我该如何把exitFlag传递给myThread类?我试着把它设置为类变量,但当我在main中设置exitFlag=1时,while not exitFlag永远不会变为真。
  2. 我该如何把queueLock传递给这个类?情况也是一样。目前它被声明为全局变量?如果我把它设置为myThread的成员变量也不行。

3 个回答

0

这是一个可以正常工作的解决方案;

mythread_class.py

import threading
import time

class MyThread (threading.Thread):
    def __init__(self, threadID, threadname, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.threadname = threadname
        self.queue = q
        self.__exitFlag = False
        self.__signal_lock = threading.Lock()

    def run(self):
        print "Starting " + self.threadname
        self.process_data()
        print "Exiting " + self.threadname

    def stop(self):
        with self.__signal_lock:
            self.__exitFlag = True

    def process_data(self):
        while not self.__exitFlag:
            if not self.queue.empty():
                data = self.queue.get()
                print "%s processing %s" % (self.threadname, data)
                time.sleep(3)
                print "%s finished processing %s" % (self.threadname, data)

            time.sleep(1)

main.py 从 mythread_class 导入 MyThread 导入队列 导入线程

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
workQueue = Queue.Queue(10)
threads = []
threadID = 1

# Create new threads
for tName in threadList:
    thread = MyThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

# Fill the queue
for word in nameList:
    workQueue.put(word)

# Wait for queue to empty
while not workQueue.empty():
    pass

# Notify threads it's time to exit
for t in threads:
    t.stop()

# Wait for all threads to complete
for t in threads:
    t.join()
print "Exiting Main Thread"

如果你有多个 MyThread 类,只需把这一行替换成你其他的类:

thread = MyThread(threadID, tName, workQueue)

--或者--

thread = MyThread2(threadID, tName, workQueue)
1

从main.py中导入你的线程类,然后在main.py中执行你想要的任何操作,不要去执行mythread.py。接着,让线程去检查exitFlag,并在main.py中修改它。

1

对于第一个问题的回答是,不要使用全局变量。相反,可以在你的myThread子类中添加一个标志。

至于第二个问题,Queue类是为了多线程编程而设计的,所以它的方法会自动处理所有需要的锁定细节,这样就能防止同时访问的问题。这意味着你其实不需要queueLock

把这两个建议结合起来,你的答案可能会变成这样(未经测试):

main.py

from mythread import MyThread
import Queue
import threading

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
workQueue = Queue.Queue(10)
threads = []
threadID = 1

# Create new threads
for tName in threadList:
    thread = MyThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

# Fill the queue
for word in nameList:
    workQueue.put(word)

# Wait for queue to empty
while not workQueue.empty():
    pass

# Notify threads it's time to exit
for t in threads:
    t.stop()

# Wait for all threads to complete
for t in threads:
    t.join()
print "Exiting Main Thread"

mythread.py

import threading
import time

class MyThread (threading.Thread):  # note capitalization change
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
        self.__exitFlag = False
        self.__signal_lock = threading.Lock()
    def run(self):
        print "Starting " + self.name
        self.process_data()
        print "Exiting " + self.name
    def stop(self):
        with self.__signal_lock:
            self.__exitFlag = True
    def process_data(self):
        while not self.__exitFlag:
            if not self.q.empty():
                data = self.q.get()
                print "%s processing %s" % (self.name, data)
                time.sleep(3)
                print "%s finished processing %s" % (self.name, data)
            time.sleep(1)

撰写回答