从 Python 调用外部命令失败并返回代码 0xC0000005 但在控制台中工作

Posted

技术标签:

【中文标题】从 Python 调用外部命令失败并返回代码 0xC0000005 但在控制台中工作【英文标题】:External command fails with return code 0xC0000005 when called from Python but works in console 【发布时间】:2016-06-21 00:45:20 【问题描述】:

我有一个在 Windows 下运行的 python 3.5 脚本,它正在调用多个文件的外部问题(准确地说是来自 BLAST+ 套件的 tblastn)。对于大多数这些文件,它运行良好,但在某些文件中,它失败并返回代码 0xC0000005。如果我采用完全相同的命令行调用并从控制台在同一当前工作目录中运行它,它会执行得很好。

我目前正在使用subprocess.Popen 运行命令,如下所示:

childProcess = subprocess.Popen(blast_cmd, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                     universal_newlines=True,shell=True)

然后调用subprocess.poll() 直到完成。我通过同时运行四个进程来实现多线程,但如果我强制它一次运行一个,它仍然会发生。 os.systemsubprocess.run()subprocess.call()subprocess.check_call() 也会发生同样的事情,无论我将 shell 设置为 True 还是 False,都会发生这种情况。

每次我运行代码时失败的文件都是相同的,但如果将相同的文件放入要处理的不同文件列表中,则相同的文件将起作用。更改调用方法有时会更改哪些文件失败,因此与subprocess.Popen 相比,使用os.system 可能会导致不同的文件失败。因此,这似乎与我在哪个文件上调用 tblastn 无关。

有谁知道是什么导致了这种行为?

或者,如果有人知道在创建的进程中运行(文档说它使用CreateProcess())与从命令行运行相比有什么不同,那么至少我可以从某个地方开始?

【问题讨论】:

我有一个关于如何调试它的想法,但我对tblastn不熟悉;你是从源代码编译它还是有能力? 我把它作为一个 .exe 得到;我可以获取源代码并重新编译它,但我不想这样做。 好的 - 我想你是在 Windows 上吗?不了解 Windows,但在 linux 上,您可以将“valgrind”添加到“blast_cmd”列表中,并为其提供一个日志文件以输出到(它是一个 valgrind arg)。这将记录失败位置的堆栈跟踪(尽管如果在调试模式下编译它会有所帮助,如果它是一个段错误)。这不是为了让您可以调试程序,而是帮助查看是否有特定的参数失败或无法加载。也许某些资源的传递方式与在 shell 上的传递方式不同(一个自动完成完整路径名,例如) 是的,在 Windows 下。我很确定这不是论证失败;它中途失败并产生不完整的 .xml 输出。 鉴于没有人可以看到环境中的明显差异,从问题的另一端处理它可能会有所帮助。如果我现在不得不猜测,那将是您在这里使用了大量数据,您的 Python 进程正在消耗额外的 RAM,因此 tblastn 内部的内存分配失败。从失败中恢复可能会阐明问题。 【参考方案1】:

错误代码很可能是“Access Denied”(虽然windows头文件中有4个代码结构,但Access Denied的可能性最大:

# for hex 0xc0000005 / decimal -1073741819
  FILE_LOG_INFORMATION_FAILED                                    iasmsg.h
# Information for the %1 log could not be logged to the text
# file %2 in the path %3. Error code: %0
  STATUS_ACCESS_VIOLATION                                        ntstatus.h
# The instruction at 0x%08lx referenced memory at 0x%08lx.
# The memory could not be %s.
  USBD_STATUS_DEV_NOT_RESPONDING                                 usb.h
# as an HRESULT: Severity: FAILURE (1), FACILITY_NULL (0x0), Code 0x5
# for hex 0x5 / decimal 5
  ERROR_ACCESS_DENIED                                            winerror.h
# Access is denied.

我将首先查看用于运行原始(启动/父)脚本的用户权限/凭据,子进程/子进程从中继承其凭据...然后将其与使用的凭据进行比较正如您所描述的那样,您“在 cmd 提示符下运行它”。

HTH, 埃德温。

【讨论】:

【参考方案2】:
    以编程方式启动的子进程通常会获得其他内存设置(堆大小等),而不是交互式启动的进程。所以尝试在 tblastn.exe 周围放置一些堆/内存检查包装器。 您对“在一个文件上失败但在另一个文件列表中处理有效”的描述表明,该错误与失败的调用本身无关,而是与先前活动引起的某些情况有关。 输出缓冲在内存中。如果 tblastn 有很多输出,请使用communicate() 来取消(或使用)子进程的输出。 shell=True 不是调用可执行文件所必需的,它是用来执行 shell 内置的。使用这个你用一个毫无意义的 cmd.exe 包装 tblastn。

【讨论】:

以上是关于从 Python 调用外部命令失败并返回代码 0xC0000005 但在控制台中工作的主要内容,如果未能解决你的问题,请参考以下文章

捕获Scala进程失败

如何在python中调用外部程序并检索输出和返回代码?

从客户端调用 DB2 外部存储过程失败并显示 CPF9810

Python 调用外部命令:subprocess 模块

Python 调用外部命令

模块XXX已加载,但对XXX的调用失败,错误代码0x80004005,何解 ?