Python Popen()失败,并带有“;[WinError 6]句柄无效";有时在_cleanup()中
我在做一个django项目。其中一个视图调用Popen()。大多数情况下,一切正常。但偶尔Popen()会失败,并显示以下错误消息:Python Popen()失败,并带有“;[WinError 6]句柄无效";有时在_cleanup()中,python,windows,python-3.x,popen,Python,Windows,Python 3.x,Popen,我在做一个django项目。其中一个视图调用Popen()。大多数情况下,一切正常。但偶尔Popen()会失败,并显示以下错误消息: Traceback (most recent call last): File "C:\***\views.py", line 116, in process_request proc = Popen(['python', exec_path, input_excel, current_tab, project]) File "C:\Python3
Traceback (most recent call last):
File "C:\***\views.py", line 116, in process_request
proc = Popen(['python', exec_path, input_excel, current_tab, project])
File "C:\Python34\lib\subprocess.py", line 754, in __init__
_cleanup()
File "C:\Python34\lib\subprocess.py", line 474, in _cleanup
res = inst._internal_poll(_deadstate=sys.maxsize)
File "C:\Python34\lib\subprocess.py", line 1146, in _internal_poll
if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0:
OSError: [WinError 6] The handle is invalid
重新启动服务器通常可以解决问题,但稍后可能会再次出现。失败后立即进行的尝试通常也会失败(通过循环实现)。多次手动重新加载页面有时会解决此问题
我还尝试了64位和32位python版本。这两方面都有问题
似乎_cleanup()管理用于避免僵尸进程的_活动列表。考虑到我使用的是windows,我注释掉了Popen()中的_cleanup(),到目前为止它似乎工作得很好。显然这不是一个合适的解决办法。还有更好的主意吗
更新:
按照埃里克森的建议,我仔细观察了把手。由于某种原因,django的autoreload.py似乎关闭了进程句柄。详情见下文
---------------------------------------------------
try handle:
Handle(908)
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "C:\Python34\lib\site-packages\django\core\management\__init__.py", line 338, in execute_from_command_line
utility.execute()
File "C:\Python34\lib\site-packages\django\core\management\__init__.py", line 330, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Python34\lib\site-packages\django\core\management\base.py", line 393, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Python34\lib\site-packages\django\core\management\commands\runserver.py", line 49, in execute
super(Command, self).execute(*args, **options)
File "C:\Python34\lib\site-packages\django\core\management\base.py", line 444, in execute
output = self.handle(*args, **options)
File "C:\Python34\lib\site-packages\django\core\management\commands\runserver.py", line 88, in handle
self.run(**options)
File "C:\Python34\lib\site-packages\django\core\management\commands\runserver.py", line 97, in run
autoreload.main(self.inner_run, None, options)
File "C:\Python34\lib\site-packages\django\utils\autoreload.py", line 325, in main
reloader(wrapped_main_func, args, kwargs)
File "C:\Python34\lib\site-packages\django\utils\autoreload.py", line 291, in python_reloader
reloader_thread()
File "C:\Python34\lib\site-packages\django\utils\autoreload.py", line 267, in reloader_thread
change = fn()
File "C:\Python34\lib\site-packages\django\utils\autoreload.py", line 204, in code_changed
for filename in gen_filenames():
File "C:\Python34\lib\site-packages\django\utils\autoreload.py", line 92, in gen_filenames
_cached_filenames = clean_files(_cached_filenames)
File "C:\Python34\lib\site-packages\django\utils\autoreload.py", line 139, in clean_files
if os.path.exists(filename):
File "C:\Python34\lib\genericpath.py", line 19, in exists
os.stat(path)
File "C:\Python34\lib\subprocess.py", line 452, in Close
print(traceback.print_stack())
None
handle closed.
---------------------------------------------------
后来异常抱怨句柄(908)。
我不太明白os.stat(path)是如何关闭句柄的,以及为什么subprocess.py没有将进程从活动列表中删除。如果进程在调用
Popen时仍在运行,那么它会被添加到\u active
列表中,以便\u cleanu
以后轮询它。子流程模块中的任何代码都不应关闭流程句柄。我怀疑其他一些代码正在调用CloseHandle
,这可能是由于以前关闭的句柄(例如文件句柄)的句柄值被重新用于子进程。某些代码可能错误地关闭了子进程的句柄。这是有道理的。但有一件事我还是很困惑。为什么句柄之后又变为有效。我注意到,通常在进程完成后,cleanup()会正常运行,而不会抱怨句柄无效。即使相同的句柄以前导致了问题。句柄是每个进程表的索引,其中包含指向内核对象的指针。关闭句柄后,表中相应的插槽和句柄值可供重用,例如用于subprocess.Popen使用的进程句柄。我在问题中更新了我认为关闭句柄的原因。但是我仍然不知道如何解决这个问题。考虑到涉及Popen
实例的引用周期,调用堆栈可能是由于异步垃圾收集造成的。但这确实表明,Popen
实例正在完成,它完成/关闭引用的句柄。如果\u active
列表中引用了Popen
实例,则不会发生这种情况。我需要做更多的工作来检测事件序列——调用跟踪、日志记录、断点(Python pdb和Windows windbg)。我想我更愿意切换到总是调用wait
方法来避免这个问题。如果在调用Popen.\uu del\uuu
时进程仍在运行,它会被添加到\u active
列表中,以便\u cleanu
以后轮询它。子流程模块中的任何代码都不应关闭流程句柄。我怀疑其他一些代码正在调用CloseHandle
,这可能是由于以前关闭的句柄(例如文件句柄)的句柄值被重新用于子进程。某些代码可能错误地关闭了子进程的句柄。这是有道理的。但有一件事我还是很困惑。为什么句柄之后又变为有效。我注意到,通常在进程完成后,cleanup()会正常运行,而不会抱怨句柄无效。即使相同的句柄以前导致了问题。句柄是每个进程表的索引,其中包含指向内核对象的指针。关闭句柄后,表中相应的插槽和句柄值可供重用,例如用于subprocess.Popen使用的进程句柄。我在问题中更新了我认为关闭句柄的原因。但是我仍然不知道如何解决这个问题。考虑到涉及Popen
实例的引用周期,调用堆栈可能是由于异步垃圾收集造成的。但这确实表明,Popen
实例正在完成,它完成/关闭引用的句柄。如果\u active
列表中引用了Popen
实例,则不会发生这种情况。我需要做更多的工作来检测事件序列——调用跟踪、日志记录、断点(Python pdb和Windows windbg)。我想我宁愿切换到总是调用wait
方法来避免这个问题。
def Close(self, CloseHandle=_winapi.CloseHandle):
print ('---------------------------------------------------')
print ('try handle:')
print (self)
if not self.closed:
self.closed = True
CloseHandle(self)
print(traceback.print_stack())
print ('handle closed.')
print ('---------------------------------------------------')