如何在Python中从多个线程收集数据?

1 投票
3 回答
2424 浏览
提问于 2025-04-16 15:40

我想在Python中使用多个线程来计算图像的像素值,最后把这些像素值组合成一张图像。不过,我在弄清楚如何把线程的结果收集回来时遇到了一些麻烦。下面是我的设置:

我创建了一个 Queue.Queue() 对象,还有一个 threading.Thread() 类的子类:

q = Queue.Queue()
class myThread(threading.Thread):
  def __init__(self, queue):
    self.queue = queue
    threading.Thread.__init__(self)
  def run(self):
    while True: # loop forever
      task = self.queue.get()
      rs = self.do_work(task) # I've got the result; now what to do with it?
      self.queue.task_done()

我的想法是,我想收集一张500x500的图像的像素数据,这张图像最开始是一个包含250,000个元素(500x500)的列表,最后会用PIL库把它变成一张图像:

pixels = array.array('B', pixels).tostring()
im = Image.fromstring('L', size, pixels)
im.show()

所以我会把每个像素的任务放进队列,然后启动一组线程:

for i in range(5):
  t = myThread(q)
  t.setDaemon(True)
  t.start()
for y in range(500):
  for x in range(500):
    q.put({'x':x, 'y':y})
q.join()

那么,如何把所有的数据收集起来呢?我觉得把这个250,000个元素的列表传给每个线程并不是个好主意,因为数据量太大,而且每个线程也会缺少其他线程的数据。

补充:对于那些在想这样做是否真的值得使用多线程的人来说,计算图像坐标的工作涉及到几个perlin噪声函数。它生成一个perlin 2D噪声点数组(一个5x5的网格),还有几个不同的频率(10x10、20x20和40x40的网格),并计算这些点之间的像素值。因此,对于最终图像中的每个像素,它需要对每个频率进行三次数学运算(计算给定点周围的X点的平均值,计算给定点周围的Y点的平均值,然后再计算这些平均值的平均值),然后在这些频率的结果之间进行加权平均。

在我的8核Mac上,我看到Python进程只使用了1个线程,并且处理器使用率达到了100%。虽然我知道我有8个核心,并且看到过一些进程显示400-600%的处理器使用率,表明它们在利用其他核心,我只是希望这个Python脚本也能做到这一点。

3 个回答

0

我想要一个全局的列表,这样每个线程都可以访问到。我之前也遇到过类似的情况,并且这样做了,没有出现问题。

1

我觉得你应该使用两个队列。

一个用来放工作或任务,另一个用来放结果。

当一个任务完成后,就把结果放到输出队列里。

2

Python有一个全局锁,用来控制对Python数据结构的修改,这个锁叫做GIL。这个锁的存在让我们在使用线程时,想要高效地做一些事情变得比较困难。

不过,不用担心!善良的开发者们为我们提供了一个叫做multiprocessing的模块。只需要把线程替换成多进程(使用multiprocessing.Process和multiprocessing.Queue),你的应用程序就变成了一个多进程应用。

至于你的问题,你需要再添加一个队列,方向要反过来。

撰写回答