OSError:[Errno 22] 子进程中的参数无效
问题描述
Python 3.3.3视窗 7
Python 3.3.3 Windows 7
Here is the full stack:
Traceback (most recent call last):
File "BlahMyScript.py", line 578, in Call
output = process.communicate( input=SPACE_KEY, timeout=600 )
File "C:Python33libsubprocess.py", line 928, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
File "C:Python33libsubprocess.py", line 1202, in _communicate
self.stdin.write(input)
OSError: [Errno 22] Invalid argument
代码如下所示:
process = subprocess.Popen( arguments,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
env=environment )
output = process.communicate( input=SPACE_KEY, timeout=600 )
此代码每天运行数百次而没有问题.但是,如果在同一台机器上运行多个脚本(相同的脚本,但有时来自不同的文件夹),我会收到错误消息.脚本未执行相同的操作(即:当我收到此错误时,另一个脚本未执行子进程).
This code runs hundreds of times a day without problems. But if more than one script is running on the same machine (the same script, but sometimes from different folders) I get the error. The scripts are not executing the same thing (i.e.: the other script is not executing a subprocess when I get this error).
subProcess 代码使用许多不同的命令行来引发错误.
The subProcess code raises the error with many different command lines fed to it.
那么,有人知道发生了什么吗?解释器是否存在多次执行(在不同进程中)的问题?通常工作得很好的相同代码,如果解释器运行相同(或非常相似)的脚本,就会出错.但他们通常执行脚本的不同部分.
So, anyone has an idea as to what is happening? Does the interpreter have a problem with multiple execution (in different processes)? Same code that normally works perfectly fine, craps out if the interpreter is running the same (or very similar) scripts. But they are usually executing different parts of the script.
我不知所措:在 8 核机器上使用单个处理器很烦人.
I'm at a loss: Using a single processor on an 8 core machine is annoying.
解决方案
以前communicate
在写入进程stdin
EPIPE错误>.从 3.3.5 开始,根据 issue 19612,它还会忽略 EINVAL
(22) 如果子进程已经退出(参见 Lib/subprocess.py 第 1199 行).
Previously communicate
only ignored an EPIPE
error when writing to the process stdin
. Starting with 3.3.5, per issue 19612, it also ignores EINVAL
(22) if the child has already exited (see Lib/subprocess.py line 1199).
背景:
process.communiciate
调用 process.stdin.write
,它调用 io.FileIO.write
,它在 Windows 上调用 C 运行时 _write
,它调用 Win32 WriteFile
(在本例中称为 NtWriteFile
,作为 IRP_MJ_WRITE
或 FastIoWrite
分派到 NamedPipe 文件系统.
process.communiciate
calls process.stdin.write
, which calls io.FileIO.write
, which on Windows calls the C runtime _write
, which calls Win32 WriteFile
(which in this case calls NtWriteFile
, which dispatches to the NamedPipe filesystem, as either an IRP_MJ_WRITE
or FastIoWrite
).
如果后者失败,它会设置一个 Windows 系统错误代码在线程中.在这种情况下,潜在的 Windows 错误可能是 ERROR_NO_DATA
(232) 因为子进程已经退出.C 运行时将其映射到 EINVAL
(22) 的 errno
值.然后由于 _write
失败,FileIO.write
根据 errno
的当前值引发 OSError
.
If the latter fails, it sets a Windows system error code in the thread. In this case the underlying Windows error is probably ERROR_NO_DATA
(232) because the child process has already exited. The C runtime maps this to an errno
value of EINVAL
(22). Then since _write
failed, FileIO.write
raises OSError
based on the current value of errno
.
附录:
如果 CRT 将 ERROR_NO_DATA
映射到 EPIPE
,则根本不会出现问题.Python 自己的 Windows 错误翻译通常遵循 CRT 的,但根据 issue 13063,它对映射 ERROR_NO_DATA
到 EPIPE
(32).因此,如果孩子已经退出,_winapi.WriteFile
会引发 BrokenPipeError
.
There wouldn't have been a problem at all if the CRT instead mapped ERROR_NO_DATA
to EPIPE
. Python's own Windows error translation generally follows the CRT's, but per issue 13063, it makes an exception to map ERROR_NO_DATA
to EPIPE
(32). Thus if the child has already exited, _winapi.WriteFile
raises BrokenPipeError
.
在子进程已经退出的情况下,以下示例复制了 EINVAL
错误.它还显示了 _winapi.WriteFile
(3.3.3 源链接)会将此错误映射到 EPIPE
.IMO,这应该被认为是微软 CRT 中的一个错误.
The following example replicates the EINVAL
error given the child process has already exited. It also shows how _winapi.WriteFile
(3.3.3 source link) would instead map this error to EPIPE
. IMO, this should be considered a bug in Microsoft's CRT.
>>> cmd = 'reg query hkcu'
>>> process = Popen(cmd, stdin=PIPE, stdout=PIPE, universal_newlines=True)
>>> process.stdin.write(' ')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument
>>> hstdin = msvcrt.get_osfhandle(process.stdin.fileno())
>>> _winapi.WriteFile(hstdin, b' ')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
BrokenPipeError: [WinError 232] The pipe is being closed
相关文章