Python队列组合

时间:2014-06-14 21:41:14

标签: python multithreading performance python-2.7 queue

说我有两个队列,称他们为colorsnumbers

colors = Queue.Queue()
numbers = Queue.Queue()

它们每个都包含几个项目:

for color in ['red', 'orange', 'yellow', 'green', 'blue', 'indago', 'violet']:
    colors.put(color)
for i in xrange(20):
    numbers.put(i)

和一个处理数字和字母组合的函数:

def handle():
    while not colors.empty()
        color = colors.get()
        number = numbers.get()
        print "Foo: %s bar: %d" % (color, number)
        colors.task_done()
        numbers.task_done()

将有线程:

children = []
for i in xrange(num_threads):
    children.append(threading.Thread(target=handle))

但我不打算只打印每种颜色和数字,而是打印所有可能的颜色和数字组合,最有效的方法是什么? 以下是我希望输出的结果:http://pastebin.com/yhksKswr

问题(我想这个功能)是Queue.get()删除它从队列返回的项目,这样每个项目只使用一次。

2 个答案:

答案 0 :(得分:2)

您可能采取的一种方法是使用元组填充单个队列,每个元组都包含“颜色”和“数字”。换句话说,生成cartesian product of the two lists作为初始步骤,然后通过线程安全的队列将它们交给线程工作者。

顺便说一下,根据我的经验,在流程级别进行并行化可以让你比在Python中使用线程更有效。您可以尝试使用Redis或Celery to distribute your jobs across many workers(在相同或不同的计算机上执行)。

答案 1 :(得分:1)

这似乎太顺序而且很小,无法进行线程化。使用并行算法解决问题的关键是必须有一种方法将其分解为大小相等的子问题,每个子问题都是合理的计算密集型(以便在创建一个值得做的新线程时产生开销)并且不需要解决前一个子问题来解决另一个子问题(因为那时一个线程在另一个线程上没有任何等待)。

您必须跟踪当前颜色和数字的含义并迭代它们,因此它看起来像这样:

for color in colors:
  for number in numbers:
    t = threading.Thread(target=make_combination, args=(color, number))
    t.run()

def make_combination(c, n):
  # make a combination

但是由于创建一个线程需要很长时间,如果你只是在循环中调用make_Combination,你会更好。

如果你真的想用线程做,我会:

  1. 使用所有颜色和数字`初始化Queue
  2. 创建n个帖子。
  3. 让每个线程获得一种颜色,复制数字队列,然后用每个数字打印颜色。
  4. 每个线程重复#3,直到颜色队列为空。
  5. 所以:

    for color in ['red', 'orange', 'yellow', 'green', 'blue', 'indago', 'violet']:
        colors.put(color)
    numbers = list(range(20)) # We won't be using it like a queue, so just make it a list.
    
    for i in range(0, num_threads):
      threading.Thread(target=handle)
    
    def handle():
      while not colors.empty():
        color = colors.get()
        for i in numbers:
          print color, i # Edit this to get it to print what you want
    

    但重要的是,这几乎不会按顺序打印。

    使用multiprocessing.Pool

    # Initialize as lists
    colors = [...]
    numbers = [...]
    
    def handle(c, n):
      # do something with c and n
    
    p = multiprocessing.Pool(num_processes)
    for c in colors:
      for n in numbers:
        p.apply_async(handle, (c, n)) # it's either this or "p.apply_async(handle, args = (c, n))". Can't remember.
        # The above basically means "call handle(c, n) in another process". There are ways to get the return value, too, if you want it. (See the docs about Pool and AsyncResult.)
    
    p.close() # No more jobs to submit.
    p.join() # Wait for jobs to finish.