Zac*_*ack 7 python multithreading stdout python-3.x
我正在研究MOOC的数据集.我有很多python3代码片段,我需要运行并从中获取结果.为此,我编写了一个循环遍历每个片段的python脚本.对于每个片段我:
sys.stdout和sys.stderr我的stringIO缓冲区threading.thread对象中执行代码段这适用于"正确"的代码,但在其他情况下这有问题:
print(),当我将其设置回默认值(远离StringIO缓冲区)时,线程开始覆盖我的实际标准输出.这会污染我的报告.这是我目前的代码:
def execCode(code, testScript=None):
# create file-like string to capture output
codeOut = io.StringIO()
codeErr = io.StringIO()
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
def worker():
exec(code, globals())
if testScript:
# flush stdout/stderror
sys.stdout.truncate(0)
sys.stdout.seek(0)
# sys.stderr.truncate(0)
# sys.stderr.seek(0)
exec(testScript)
thread = threading.Thread(target=worker, daemon=True)
# thread = Process(target=worker) #, stdout=codeOut, stderr=codeErr)
thread.start()
thread.join(0.5) # 500ms
execError = codeErr.getvalue().strip()
execOutput = codeOut.getvalue().strip()
if thread.is_alive():
thread.terminate()
execError = "TimeError: run time exceeded"
codeOut.close()
codeErr.close()
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
# restore any overridden functions
restoreBuiltinFunctions()
if execError:
return False, stripOuterException(execError)
else:
return True, execOutput
Run Code Online (Sandbox Code Playgroud)
为了处理这种情况,我一直在尝试使用multithreading.Process和/或contextlib.redirect_stdout在一个进程中运行代码(然后我可以调用process.terminate()),但是我没有成功捕获stdout/stderr.
所以我的问题是:如何从进程重定向或捕获stdout/stderr?或者,还有其他方法可以尝试运行并捕获任意代码的输出吗?
(是的,我知道这通常是一个坏主意;我在虚拟机中运行它,以防万一有恶意代码)
Python版本是3.5.3
在我看来,在这种情况下有一点灵活性.我有一个函数,preprocess(code)它接受代码提交作为字符串并改变它.大多数情况下,我一直用它来使用正则表达式替换一些变量的值.
这是一个示例实现:
def preprocess(code):
import re
rx = re.compile('earlier_date\s*=\s*.+')
code = re.sub(rx, "earlier_date = date(2016, 5, 3)", code)
rx = re.compile('later_date\s*=\s*.+')
code = re.sub(rx, "later_date = date(2016, 5, 24)", code)
return code
Run Code Online (Sandbox Code Playgroud)
我可以使用预处理功能来帮助重定向STDOUT
在 Python 中与正在运行的进程通信并不简单。由于某种原因,您只能在子流程生命周期中执行一次。根据我的经验,最好运行一个线程来启动一个进程,并在超时后获取其输出并终止子进程。
就像是:
def subprocess_with_timeout(cmd, timeout_sec, stdin_data=None):
"""Execute `cmd` in a subprocess and enforce timeout `timeout_sec` seconds.
Send `stdin_data` to the subprocess.
Return subprocess exit code and outputs on natural completion of the subprocess.
Raise an exception if timeout expires before subprocess completes."""
proc = os.subprocess.Popen(cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
timer = threading.Timer(timeout_sec, proc.kill)
# this will terminate subprocess after timeout
timer.start()
# you will be blocked here until process terminates (by itself or by timeout death switch)
stdoutdata, stderrdata = proc.communicate(stdin_data)
if timer.is_alive():
# Process completed naturally - cancel timer and return exit code
timer.cancel()
return proc.returncode, stdoutdata, stderrdata
# Process killed by timer - raise exception
raise TimeoutError('Process #%d killed after %f seconds' % (proc.pid, timeout_sec))
Run Code Online (Sandbox Code Playgroud)
因此,运行一个调用subprocess_with_timeout. 它应该处理输入并保存结果。
另一个想法是使用网络服务器来执行 IPC。请参阅此链接
| 归档时间: |
|
| 查看次数: |
477 次 |
| 最近记录: |