是否有办法检查我的代码的哪一部分离开文件句柄打开



是否有方法跟踪python进程以检查文件正在打开的位置。当我在运行过程中使用lsof时,我打开了太多文件,但我不确定它们在哪里被打开。

ls /proc/$pid/fd/ | wc -l

我怀疑我正在使用的库之一可能没有正确处理文件。是否有一种方法可以准确地隔离我的python代码中的哪一行文件正在打开?

在我的代码中,我使用第三方库来处理数千个媒体文件,由于它们被打开,我收到错误

OSError: [Errno 24] Too many open files

运行几分钟后。现在我知道提高打开文件的限制是一个选项,但这只会把错误推到以后的时间点。

跟踪open调用的最简单方法是在Python中使用审计钩子。注意,这个方法只会跟踪Python的open调用,而不是系统调用。

fdmod.py为单个功能的模块文件foo:

def foo():
return open("/dev/zero", mode="r")

现在文件fd_trace.py中的主代码,跟踪所有open调用并导入fdmod,定义如下:

import sys
import inspect
import fdmod
def open_audit_hook(name, *args):
if name == "open":
print(name, *args, "was called:")
caller = inspect.currentframe()
while caller := caller.f_back:
print(f"tFunction {caller.f_code.co_name} "
f"in {caller.f_code.co_filename}:"
f"{caller.f_lineno}"
)
sys.addaudithook(open_audit_hook)
# main code
fdmod.foo()
with open("/dev/null", "w") as dev_null:
dev_null.write("hi")
fdmod.foo()

当我们运行fd_trace.py时,当某个组件调用open时,我们将打印调用堆栈:

% python3 fd_trace.py
open ('/dev/zero', 'r', 524288) was called:
Function foo in /home/tkrennwa/fdmod.py:2
Function <module> in fd_trace.py:17
open ('/dev/null', 'w', 524865) was called:
Function <module> in fd_trace.py:18
open ('/dev/zero', 'r', 524288) was called:
Function foo in /home/tkrennwa/fdmod.py:2
Function <module> in fd_trace.py:20

详情见sys.audithookinspect.currentframe

您可以使用strace获得有用的信息。这将显示进程发出的所有系统调用,包括对open()的调用。它不会直接显示Python代码中这些调用发生的位置,但您可以从上下文中推断出一些信息。

查看打开的文件句柄在Linux上很容易:

open_file_handles = os.listdir('/proc/self/fd')
print('open file handles: ' + ', '.join(map(str, open_file_handles)))

您也可以在任何操作系统(例如Windows, Mac)上使用以下命令:

import errno, os, resource
open_file_handles = []
for fd in range(resource.getrlimit(resource.RLIMIT_NOFILE)[0]):
try: os.fstat(fd)
except OSError as e:
if e.errno == errno.EBADF: continue
open_file_handles.append(fd)
print('open file handles: ' + ', '.join(map(str, open_file_handles)))

注意:如果你实际(偶尔)用完文件句柄,这应该总是有效的。通常最多有256个文件句柄。但如果最大(由操作系统/用户策略设置)是一个巨大的东西,如十亿,则可能需要很长时间。

还要注意:几乎总是有至少三个文件句柄分别为STDIN, STDOUT和STDERR打开。

最新更新