【问题标题】:Python - Threading and a While True LoopPython - 线程和 While True 循环
【发布时间】:2009-04-30 19:57:07
【问题描述】:

我有一个将行附加到 self.output 的线程和一个循环,直到 self.done 为 True(或达到最大执行时间)。

除了使用一个不断检查是否完成的while循环之外,有没有更有效的方法来做到这一点。 while 循环导致 CPU 在运行时达到 100%。

time.clock()
while True:

    if len(self.output):
        yield self.output.pop(0)

    elif self.done or 15 < time.clock():
        if 15 < time.clock():
            yield "Maximum Execution Time Exceeded %s seconds" % time.clock()
        break

【问题讨论】:

    标签: python multithreading loops


    【解决方案1】:

    您的线程是否在此处附加到 self.output,而您的主要任务正在使用它们?如果是这样,这是为Queue.Queue 量身定做的工作。你的代码应该是这样的:

    import Queue
    
    # Initialise queue as:
    queue = Queue.Queue()
    Finished = object()   # Unique marker the producer will put in the queue when finished
    
    # Consumer:
    try:
        while True:
            next_item = self.queue.get(timeout=15)
            if next_item is Finished: break
            yield next_item
    
    except Queue.Empty:
        print "Timeout exceeded"
    

    您的生产者线程使用 queue.put(item) 将项目添加到队列中

    [编辑] 原始代码在检查 self.done 时存在竞争问题(例如,在设置标志之前可能会将多个项目附加到队列中,导致代码在第一)。更新了来自 ΤZΩΤZΙΟΥ 的建议 - 生产者线程应改为将特殊令牌(已完成)附加到队列以指示它已完成。

    注意:如果您有多个生产者线程,则需要一种更通用的方法来检测它们何时全部完成。您可以使用相同的策略来完成此操作 - 每个线程都有一个 Finished 标记,并且消费者在看到 num_threads 个标记时终止。

    【讨论】:

    • OoOooo,现在我们正在谈论。 :D
    • 有没有办法告诉 Queue.get() 上的线程阻塞而没有超时,生产者已将任何内容放入线程中,以便它可以干净地退出?
    • @Sii:您可以在创建线程时将其标记为守护进程。这意味着当您的程序退出时线程将退出。
    • 生产者应该在队列中放置一个特殊的标记,表明它已经完成了。要么执行done_marker= object() 并使用它,要么您可以使用 Ellipsis 对象(否则通常无用)。
    • 我应该注意到你的例子有一个缺陷,if self.done: break 应该改为:if self.done and self.queue.empty(): break,否则队列中的最后一项不一定会被包括在内。花了我一些时间来解决这个问题。
    【解决方案2】:

    使用信号量;让工作线程在完成后释放它,并阻止附加线程,直到工作线程完成信号量。

    即。在工作人员中,在工作开始时执行self.done = threading.Semaphore() 之类的操作,完成时执行self.done.release() 之类的操作。在您上面提到的代码中,只需执行 self.done.acquire() 即可,而不是忙循环。当工作线程完成后,控制权将返回。

    编辑:不过,恐怕我没有解决您需要的超时值;这个issue 描述了标准库中信号量超时的需要。

    【讨论】:

      【解决方案3】:

      使用 time.sleep(seconds) 在 while 循环的每次迭代后创建一个短暂的暂停以释放 CPU。您必须根据完成后快速完成工作的重要性来设置每次迭代期间的睡眠时间。

      例子:

      time.clock()
      while True:
      
          if len(self.output):
              yield self.output.pop(0)
      
          elif self.done or 15 < time.clock():
              if 15 < time.clock():
                  yield "Maximum Execution Time Exceeded %s seconds" % time.clock()
                  break
      
          time.sleep(0.01) # sleep for 10 milliseconds
      

      【讨论】:

      • 睡眠通常会导致性能不佳。您应该在使用 sleep 之前考虑同步。
      【解决方案4】:

      使用互斥模块或事件/信号量

      【讨论】:

        【解决方案5】:

        您必须在此处使用同步原语。看这里:http://docs.python.org/library/threading.html

        事件对象看起来很简单,应该可以解决您的问题。您还可以使用条件对象或信号量。

        我没有发布示例,因为我从未使用过 Event 对象,而且替代方案可能不太简单。


        编辑:我不确定我是否理解您的问题。如果线程可以等到某个条件得到满足,请使用同步。否则有人发布的sleep() 解决方案会占用过多的 CPU 时间。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-23
          • 2015-06-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-28
          相关资源
          最近更新 更多