在Python 2.6中使用队列类
假设我一直在使用Python2.6,并且无法升级(即使这会有所帮助)。我已经编写了一个使用Queue类的程序。我的生产者是一个简单的目录列表。我的消费者线程从队列中提取一个文件,并处理它。如果该文件已被处理,我将跳过它。已处理列表是在所有线程启动之前生成的,因此它不是空的 这里有一些伪代码在Python 2.6中使用队列类,python,multithreading,queue,Python,Multithreading,Queue,假设我一直在使用Python2.6,并且无法升级(即使这会有所帮助)。我已经编写了一个使用Queue类的程序。我的生产者是一个简单的目录列表。我的消费者线程从队列中提取一个文件,并处理它。如果该文件已被处理,我将跳过它。已处理列表是在所有线程启动之前生成的,因此它不是空的 这里有一些伪代码 import Queue, sys, threading processed = [] def consumer(): while True: file = dirlist.get
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中队列/线程类的预期行为?我尝试运行您的代码,但没有看到您描述的行为。然而,该程序从未退出。我建议更改
.get()
调用,如下所示:
try:
file = dirlist.get(True, 1)
except Queue.Empty:
return
如果想知道当前正在执行哪个线程,可以导入模块并打印
我在.get()之后添加了以下行:
并得到以下输出:
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
由于线程同时向标准输出写入数据,因此输出混乱。各种线程标识符进一步确认所有线程都在运行
可能真实代码或测试方法中有错误,但您发布的代码中没有错误?由于此问题仅在查找已处理的文件时出现,因此这似乎与已处理的列表本身有关。你试过实现一个简单的锁吗?例如:
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一次只能从一个线程运行代码。在这种情况下,您可能需要切换到多处理
模块-这与线程化
非常相似,但您需要用另一个解决方案替换共享变量(请参阅以了解详细信息)。一定出了什么问题-怎么能指望暂停依赖于与队列完全无关的测试?!但是我不认为它在这段代码中,尽管它有缺陷(线程不是守护进程,滥用内置名称文件,…)--我不认为这些会让线程停止!更确切地说,处理是如何填充的,以及它在“…”部分中是否发生过更改(这可能是一个问题,因为它周围没有锁)?你能用少量的已处理文件(例如,将一半的文件放在那里)和少量的“…”(例如,打印文件
)重现这个问题吗?我没有想到在已处理列表上加锁。现在我想起来了,这肯定是有道理的。谢谢你推荐我使用多处理模块。啊,这就解释了为什么我不得不一直终止这个程序。谢谢你的提示。@voipme谢谢你。向上投票更好。:-)
processed = []
processed_lock = threading.Lock()
def consumer():
while True:
with processed_lock.acquire():
fileInList = file in processed
if fileInList:
# ... et cetera