【问题标题】:Python Queue CombinationPython队列组合
【发布时间】:2014-06-14 21:41:13
【问题描述】:

假设我有两个队列,分别叫它们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() 删除了它从队列中返回的项目,以便每个项目只使用一次。

【问题讨论】:

  • 使用itertools。你描述的问题似乎与Queue无关。
  • @BrianCain 我使用Queue 的原因是我不必担心线程安全。我知道如何处理列表,但不知道队列。

标签: python multithreading performance python-2.7 queue


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    似乎这可能太连续且太小而无法线程化。使用并行算法解决问题的关键是必须有一种方法将其分解为大小大致相等的子问题,每个子问题的计算量都相当大(以使创建新线程的开销值得做) ,并且不需要解决前一个子问题来解决另一个子问题(因为这样一个线程就没有在等待另一个线程了)。

    您将不得不跟踪当前的颜色和数字是什么并遍历它们,所以它可能看起来像这样:

    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 直到颜色队列为空。

    所以:

    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.
    

    【讨论】:

    • 感谢您的回答。我正在编写的实际程序实际上确实为每种组合提供了一个计算密集度更高的过程,我只使用颜色和数字来简化问题。此外,您的解决方案无法控制创建的线程数。如果有 1000 个数字,它会尝试创建数千个线程。
    • 哦,如果你真的想要并发,那么你需要多处理。由于 GIL,Python 中的线程一次只能运行一个。多个进程绕过 GIL 并为您提供真正的 SMP。它甚至还有一个Pool 类,可以处理将进程数限制为给定数量的问题。您是否有兴趣查看使用 Pool 的示例?
    • 以前从未听说过该模块,但它听起来很闪亮,所以是的!
    • AFAIK,它不在图书馆。出于好奇,我做了一个粗略的谷歌搜索。无论如何,如果您想一次实际使用多个处理器内核,则无论如何都需要multiprocessing 而不是threading。如果您使用线程,您会注意到无论您创建多少线程,它们都只使用您机器上的一个内核。进程,如使用 multiprocessing 模块创建的进程,也将使用任意数量的内核(当然,受限于你拥有的内核数量)。
    • 这并不是说您不能编写 ThreadPool 类。但我不明白其中的意义。很抱歉打断你的想法,但我和大多数人一样,认为 Python 中的线程完全没用,因为 GIL(谷歌它)。如果他们能修复 GIL,那就太好了,但似乎永远不会发生。
    猜你喜欢
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多