【问题标题】:Python multiprocessing apply_async + ValuePython 多处理 apply_async + 值
【发布时间】:2012-12-27 13:01:30
【问题描述】:

我尝试通过 apply_async 将共享计数器传递给多处理中的任务,但它失败并出现这样的错误“RuntimeError:同步对象只能通过继承在进程之间共享”。怎么回事

def processLine(lines, counter, mutex):
    pass

counter = multiprocessing.Value('i', 0)
mutex = multiprocessing.Lock()
pool = Pool(processes = 8)
lines = []

for line in inputStream:
    lines.append(line)
    if len(lines) >= 5000:
         #don't queue more than 1'000'000 lines
         while counter.value > 1000000:
                 time.sleep(0.05)
         mutex.acquire()
         counter.value += len(lines)
         mutex.release()
         pool.apply_async(processLine, args=(lines, counter, ), callback = collectResults)
         lines = []

【问题讨论】:

    标签: python multiprocessing counter shared


    【解决方案1】:

    让池处理调度:

    for result in pool.imap(process_single_line, input_stream):
        pass
    

    如果顺序无关紧要:

    for result in pool.imap_unordered(process_single_line, input_stream):
        pass
    

    pool.*map*() 函数有 chunksize 参数,您可以更改它以查看它是否会影响您的情况下的性能。

    如果您的代码需要在一次调用中传递多行:

    from itertools import izip_longest
    
    chunks = izip_longest(*[iter(inputStream)]*5000, fillvalue='') # grouper recipe
    for result in pool.imap(process_lines, chunks):
        pass
    

    限制排队项目数量的一些替代方法是:

    • multiprocessing.Queue 设置最大大小(在这种情况下您不需要池)。 queue.put() 将在达到最大大小时阻塞,直到其他进程调用 queue.get()
    • 使用 Condition 或 BoundedSemaphor 等多处理原语手动实现生产者/消费者模式。

    注意:每个Value都有关联的锁,不需要单独的锁。

    【讨论】:

      【解决方案2】:

      我用这种不优雅的方式解决了它

      def processLine(lines):
          pass
      
      def collectResults(result):
          global counter
          counter -= len(result)
      
      counter = 0
      pool = Pool(processes = 8)
      lines = []
      
      for line in inputStream:
          lines.append(line)
          if len(lines) >= 5000:
               #don't queue more than 1'000'000 lines
               while counter.value > 1000000:
                   time.sleep(0.05)
               counter.value += len(lines)
               pool.apply_async(processLine, args=(lines), callback = collectResults)
               lines = []
      

      【讨论】:

      • 我知道这是一些最小的 sn-p,但我担心你的回调函数没有达到你的预期。由于processLine 没有返回值,因此您真的不应该调用len(result),因为它没有任何意义。如果您要回答自己的问题,则应使其完全独立。
      猜你喜欢
      • 2019-04-05
      • 1970-01-01
      • 2020-10-30
      • 1970-01-01
      • 1970-01-01
      • 2018-07-26
      • 2016-08-17
      • 2020-08-29
      • 2013-01-26
      相关资源
      最近更新 更多