我的一个单元测试有一个幻像问题。
我使用ThreadPool
multiprocessing
包中的stdout
来利用stderr
从我的班级中包装paramiko
和ThreadPool
个功能。在创建过程中,我使用下面的代码进行了一些真实的测试,它运行良好。但在编写代码的单元测试期间,我设法遇到了问题, 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}}
答案 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()