线程/队列挂起问题

时间:2014-02-14 03:11:19

标签: python multithreading queue

新手要在这里进行线程化。在尝试使用线程/队列构建我的第一个脚本时,我从这个thread借了很多代码:

import threading, urllib2
import Queue
import sys
from PIL import Image
import io, sys

def avhash(url,queue):
    if not isinstance(url, Image.Image):
        try:
            im = Image.open(url)
        except IOError:
            fd=urllib2.urlopen(url)
            image_file=io.BytesIO(fd.read())
            im=Image.open(image_file)
            im = im.resize((8, 8), Image.ANTIALIAS).convert('L')
            avg = reduce(lambda x, y: x + y, im.getdata()) / 64.
    hash = reduce(lambda x, (y, z): x | (z << y),
                  enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())),
                  0)

    queue.put({url:hash})
    queue.task_done()

def fetch_parallel(job_list):
    q = Queue.Queue()
    threads = [threading.Thread(target=avhash, args = (job,q)) for job in job_list[0:50]]
    for t in threads:
        t.daemon = True
        t.start()

    for t in threads:
        t.join()
    return [q.get() for _ in xrange(len(job_list))]

在这种情况下,job_list是一个URL列表。我发现当这个列表等于或小于50时,此代码工作正常,但是当&gt;时它会挂起50.必须有一些我从根本上不了解线程如何工作的东西?

1 个答案:

答案 0 :(得分:0)

你的问题就在这一行:

return [q.get() for _ in xrange(len(job_list))]

如果job_list包含的元素超过50个,那么您尝试从队列中读取的结果比您输入的更多。因此:

return [q.get() for _ in xrange(len(job_list[:50]))]

或者,甚至更好:

MAX_LEN = 50
...
threads = [... for job in job_list[:MAXLEN]]
...
return [q.get() for _ in job_list[:MAXLEN]]

[编辑]

您似乎希望您的程序能够执行与其不同的操作。您的程序获取job_list中的前50个条目,处理线程中的每个条目并忽略所有其他作业。从下面的评论中我假设您想要处理所有工作,但一次只能处理50个工作。为此,您应该使用线程池。在Python&gt; = 3.2中,您可以使用concurrent.futures.ThreadPoolExecutor [link]

在Python&lt; 3.2你必须自己动手:

CHUNK_SIZE = 50

def fetch_parallel(job_list):
    results = []
    queue = Queue.Queue()
    while job_list:
        threads = [threading.Thread(target=avhash, args=(job, queue))
                      for job in job_list[:CHUNK_SIZE]]
        job_list = job_list[CHUNK_SIZE:]
        for thread in threads:
            thread.daemon = True
            thread.start()
        for thread in threads:
            thread.join()
        results.extend(queue.get() for _ in threads)
    return results

(未测试的)

[/编辑]