Python 有没有办法检查我的代码中哪一部分使文件句柄保持打开状态

Python 有没有办法检查我的代码中哪一部分使文件句柄保持打开状态,python,python-3.x,file-handling,Python,Python 3.x,File Handling,是否有一种方法可以跟踪python进程以检查文件的打开位置。当我在运行进程中使用lsof时,打开的文件太多,但我不确定它们是在哪里打开的 ls /proc/$pid/fd/ | wc -l 我怀疑我正在使用的一个库可能没有正确处理这些文件。有没有一种方法可以准确地隔离文件在python代码中的哪一行被打开 在我的代码中,我与第三方库一起处理数千个媒体文件,由于它们处于打开状态,我收到了错误消息 OSError: [Errno 24] Too many open files 跑了几分钟后。现在

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

ls /proc/$pid/fd/ | wc -l
我怀疑我正在使用的一个库可能没有正确处理这些文件。有没有一种方法可以准确地隔离文件在python代码中的哪一行被打开

在我的代码中,我与第三方库一起处理数千个媒体文件,由于它们处于打开状态,我收到了错误消息

OSError: [Errno 24] Too many open files

跑了几分钟后。现在我知道提高打开文件的限制是一种选择,但这只会将错误推到以后的某个时间点。

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

跟踪
打开的调用的最简单方法是在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
%python3 fd\u trace.py
调用了open('/dev/zero',r',524288):
函数foo in/home/tkrennwa/fdmod.py:2
fd_trace.py中的函数:17
调用了open('/dev/null',w',524865):
fd_trace.py中的函数:18
调用了open('/dev/zero',r',524288):
函数foo in/home/tkrennwa/fdmod.py:2
fd_trace.py中的函数:20

有关详细信息,请参阅和。

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

open_file_handles = os.listdir('/proc/self/fd')
print('open file handles: ' + ', '.join(map(str, open_file_handles)))
您还可以在任何操作系统(如Windows、Mac)上使用以下功能:

注意:假设您实际上(偶尔)用完了文件句柄,这应该总是有效的。通常最多有256个文件句柄。但是,如果最大值(由操作系统/用户策略设置)达到10亿左右,可能需要很长时间


另外请注意:对于STDIN、STDOUT和STDERR,几乎总是会分别打开至少三个文件句柄。

您是使用
open()
还是使用
with open()
语句打开文件?我使用
with
命令,但正如我所说的,一些文件访问是通过其他库进行的。它们是像音频文件一样的媒体文件。好吧,既然你没有提供你的代码片段,我就在这里暗中拍摄。您是否可以向这些库发送文件描述符而不是文件名,这样您就可以只打开一次文件!“打开的文件太多”是什么意思?大概是库打开文件的原因吧。更新了问题,更详细地解释了我所说的文件太多的意思
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)))