来自python的多处理的ThreadPool熄灭了

时间:2016-04-19 16:26:39

标签: python multithreading threadpool

我的一个单元测试有一个幻像问题。 我使用ThreadPool multiprocessing包中的stdout来利用stderr从我的班级中包装paramikoThreadPool个功能。在创建过程中,我使用下面的代码进行了一些真实的测试,它运行良好。但在编写代码的单元测试期间,我设法遇到了问题, while not (self.__stdout_async_r.ready() and self.__stderr_async_r.ready()): time.sleep(WAIT_FOR_DATA) 的这种用法一直没用。

这一部分在95%的时间内都会挂起,并且有时会以某种方式正确执行。

import time
from multiprocessing.pool import ThreadPool

class ExecResult(object):
  def __init__(self, command=None, exit_status_func=None, 
               receive_stdout_func=None, receive_stderr_func=None,
               connection=None):
    self.connection = connection
    self.stdout = None
    self.stderr = None
    self.ecode = None
    self.ts_stop = None
    self._exit_status_f = exit_status_func
    self.result_available = False
    self.__fetch_streams(receive_stdout_func, receive_stderr_func)

  def wait_for_data(self):
    WAIT_FOR_DATA = 0.1

    if not self.result_available:

      # Here it hangs out for 95 percent
      while not (self.__stdout_async_r.ready() and self.__stderr_async_r.ready()):
        time.sleep(WAIT_FOR_DATA)

      self.result_available = True
      self.ts_stop = time.time()
      self.stdout = self.__stdout_async_r.get(timeout=2)
      self.stderr = self.__stderr_async_r.get(timeout=2)
      self.ecode = self._exit_status_f()


  def __fetch_streams(self, stdout_func, stderr_func):
    stdout_t = ThreadPool(processes=1)
    stderr_t = ThreadPool(processes=1)

    self.__stdout_async_r = stdout_t.apply_async(func=stdout_func)
    self.__stderr_async_r = stderr_t.apply_async(func=stderr_func)
    stdout_t.close()
    stderr_t.close()

def stderr():
  return "stderr"

def stdout():
  return "stdout"

def exit():
  return "0"

# actual reproduction
res = ExecResult(None, exit, stdout, stderr, None)
res.wait_for_data() #if are data available get them or wait
print res.stdout
print res.stderr
print res.ecode

我在调试过程中检查了这些值,并且我发现有时候有一个或其他条件设置为完成但另一个不是。但这两个功能都已经完成,因此结果只是要求将来永远不会改变的状态。

重现的代码(具有此问题所需的功能):

{{1}}

1 个答案:

答案 0 :(得分:1)

通常情况下,经过一段时间的诅咒和喝茶后,我找到了答案。

解决方案是在关闭方法后添加:

stdout_t.join()
stderr_t.join()

所以这是整个修复过的部分:

def __fetch_streams(self, stdout_func, stderr_func):
    stdout_t = ThreadPool(processes=1)
    stderr_t = ThreadPool(processes=1)

    self.__stdout_async_r = stdout_t.apply_async(func=stdout_func)
    self.__stderr_async_r = stderr_t.apply_async(func=stderr_func)
    stdout_t.close()
    stderr_t.close()
    stdout_t.join()
    stderr_t.join()