在Python 2.6中使用Queue类

时间:2010-04-16 01:38:01

标签: python multithreading queue

让我们假设我使用Python 2.6,并且无法升级(即使这会有所帮助)。我编写了一个使用Queue类的程序。我的制作人是一个简单的目录列表。我的消费者线程从队列中提取文件,然后用它做任务。如果文件已经处理过,我跳过它。处理后的列表是在所有线程启动之前生成的,所以它不是空的。

这是一些伪代码。

import Queue, sys, threading

processed = []

def consumer():
    while True:
        file = dirlist.get(block=True)
        if file in processed:
            print "Ignoring %s" % file
        else:
            # do stuff here
        dirlist.task_done()

dirlist = Queue.Queue()

for f in os.listdir("/some/dir"):
    dirlist.put(f)

max_threads = 8

for i in range(max_threads):
    thr = Thread(target=consumer)
    thr.start()

dirlist.join()

我得到的一个奇怪的行为是,如果一个线程遇到一个已经处理过的文件,那么该线程会停止并等待整个程序结束。我做了一些测试,前7个线程(假设8是最大值)停止,而第8个线程继续处理,一次一个文件。但是,通过这样做,我失去了线程化应用程序的全部理由。

我做错了什么,或者这是Python 2.6中Queue / threading类的预期行为?

2 个答案:

答案 0 :(得分:2)

我尝试运行您的代码,但没有看到您描述的行为。但是,程序永远不会退出。我建议更改.get()电话,如下所示:

    try:
        file = dirlist.get(True, 1)
    except Queue.Empty:
        return

如果您想知道当前正在执行哪个线程,可以导入thread模块并打印thread.get_ident()

我在.get()

之后添加了以下行
    print file, thread.get_ident()

并获得以下输出:

bin 7116328
cygdrive 7116328
 cygwin.bat 7149424
cygwin.ico 7116328
 dev etc7598568
7149424
 fix 7331000
 home 7116328lib
 7598568sbin
 7149424Thumbs.db
 7331000
tmp 7107008
 usr 7116328
var 7598568proc
 7441800

输出很乱,因为线程同时写入stdout。各种线程标识符进一步确认所有线程都在运行。

在实际代码或测试方法中可能有问题,但在您发布的代码中却没有?

答案 1 :(得分:1)

由于此问题仅在查找已经处理过的文件时才会显现,因此这似乎与processed列表本身有关。你试过实现一个简单的锁吗?例如:

processed = []
processed_lock = threading.Lock()

def consumer():
    while True:
        with processed_lock.acquire():
            fileInList = file in processed
        if fileInList:
            # ... et cetera

线程往往会导致最奇怪的错误,即使它们似乎“不应该”发生。在共享变量上使用锁定是确保您不会遇到可能导致线程死锁的某种竞争条件的第一步。


当然,如果你在# do stuff here下所做的事情是CPU密集型的,那么由于全局解释器锁,Python一次只能从一个线程运行代码。在这种情况下,您可能希望切换到multiprocessing模块 - 它与threading非常相似,但您需要使用其他解决方案替换共享变量(有关详细信息,请参阅here)。