新手要在这里进行线程化。在尝试使用线程/队列构建我的第一个脚本时,我从这个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.必须有一些我从根本上不了解线程如何工作的东西?
答案 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
(未测试的)
[/编辑]