Me aparece un error en un programa que se supone que debe ejecutarse durante un tiempo prolongado en el que hay demasiados archivos abiertos. ¿Hay alguna forma de que pueda hacer un seguimiento de qué archivos están abiertos para poder imprimir esa lista de vez en cuando y ver dónde está el problema?compruebe qué archivos están abiertos en Python
Respuesta
Terminé envolviendo el objeto de archivo incorporado en el punto de entrada de mi programa. Descubrí que no estaba cerrando mis registradores.
import __builtin__
openfiles = set()
oldfile = __builtin__.file
class newfile(oldfile):
def __init__(self, *args):
self.x = args[0]
print "### OPENING %s ###" % str(self.x)
oldfile.__init__(self, *args)
openfiles.add(self)
def close(self):
print "### CLOSING %s ###" % str(self.x)
oldfile.close(self)
openfiles.remove(self)
oldopen = __builtin__.open
def newopen(*args):
return newfile(*args)
__builtin__.file = newfile
__builtin__.open = newopen
def printOpenFiles():
print "### %d OPEN FILES: [%s]" % (len(openfiles), ", ".join(f.x for f in openfiles))
Supongo que tiene filtraciones de descriptores de archivos. Es probable que desee revisar su código para asegurarse de que está cerrando todos los archivos que abre.
Me imaginé que ese era el problema. Sin embargo, el código es muy complejo, y esta sería una manera fácil de detectar inmediatamente qué archivos no se están cerrando. – Claudiu
En Windows, puede usar Process Explorer para mostrar todos los identificadores de archivos que pertenecen a un proceso.
En Linux, puede usar lsof
para mostrar todos los archivos abiertos por un proceso.
Tiene python alguna función interna para lsof, o realmente tengo que llamar a Linux lsof? – sumid
En Linux, se puede ver el contenido de /proc/self/fd
:
$ ls -l /proc/self/fd/
total 0
lrwx------ 1 foo users 64 Jan 7 15:15 0 -> /dev/pts/3
lrwx------ 1 foo users 64 Jan 7 15:15 1 -> /dev/pts/3
lrwx------ 1 foo users 64 Jan 7 15:15 2 -> /dev/pts/3
lr-x------ 1 foo users 64 Jan 7 15:15 3 -> /proc/9527/fd
¿Es esto solo para CPython o todas las implementaciones? Recuerdo haber visto, creo, que los archivos abiertos en ipython se enumeran en '/ proc/ipython_pid/fd /'. Además, en la lista anterior, ¿cómo sabe qué archivos abrió y qué archivos abrió Python (y cuáles no debería cerrar)? – Chris
Esto es para sistemas Linux que proporcionan el sistema de archivos '/ proc'. Es independiente del lenguaje; cualquier programa en cualquier idioma que pueda acceder a los "archivos" en '/ proc' puede obtener esta información. No me he equivocado con ipython, pero la idea básica sería registrar el contenido de '/ proc/self/fd' después de la inicialización y luego comparar los contenidos más adelante en la ejecución para buscar cambios. –
Aunque las soluciones anteriores que envuelven abre son útiles para el propio código de uno, estaba depurando mi cliente a una biblioteca de terceros incluyendo algún código de extensión c, así que necesitaba una forma más directa. Los siguientes trabajos de rutina en virtud de Darwin, y (espero) otros entornos de tipo Unix:
def get_open_fds():
'''
return the number of open file descriptors for current process
.. warning: will only work on UNIX-like os-es.
'''
import subprocess
import os
pid = os.getpid()
procs = subprocess.check_output(
[ "lsof", '-w', '-Ff', "-p", str(pid) ])
nprocs = len(
filter(
lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(),
procs.split('\n'))
)
return nprocs
Si alguien puede extender para ser portátil para ventanas, yo estaría muy agradecido.
downvoted por mal estilo. pep8! – Newb
Existen algunas limitaciones a la respuesta aceptada, ya que no parece contar las canalizaciones. Tenía una secuencia de comandos python que abrió muchos subprocesos y no cerró correctamente las canalizaciones de entrada, salida y error estándar, que se usaron para la comunicación. Si utilizo la respuesta aceptada, no podrá contar estas canalizaciones abiertas como archivos abiertos, pero (al menos en Linux) son archivos abiertos y cuentan para el límite de archivos abiertos. La solución lsof -p
sugerida por sumid y shunc funciona en esta situación, porque también muestra las tuberías abiertas.
Obtenga una lista de todos los archivos abiertos. handle.exe
es parte de Sysinternals Suite de Microsoft. Una alternativa es el módulo psutil Python, pero encuentro que 'handle' imprimirá más archivos en uso.
Esto es lo que hice. Kludgy código de advertencia.
#!/bin/python3
# coding: utf-8
"""Build set of files that are in-use by processes.
Requires 'handle.exe' from Microsoft SysInternals Suite.
This seems to give a more complete list than using the psutil module.
"""
from collections import OrderedDict
import os
import re
import subprocess
# Path to handle executable
handle = "E:/Installers and ZIPs/Utility/Sysinternalssuite/handle.exe"
# Get output string from 'handle'
handle_str = subprocess.check_output([handle]).decode(encoding='ASCII')
""" Build list of lists.
1. Split string output, using '-' * 78 as section breaks.
2. Ignore first section, because it is executable version info.
3. Turn list of strings into a list of lists, ignoring first item (it's empty).
"""
work_list = [x.splitlines()[1:] for x in handle_str.split(sep='-' * 78)[1:]]
""" Build OrderedDict of pid information.
pid_dict['pid_num'] = ['pid_name','open_file_1','open_file_2', ...]
"""
pid_dict = OrderedDict()
re1 = re.compile("(.*?\.exe) pid: ([0-9]+)") # pid name, pid number
re2 = re.compile(".*File.*\s\s\s(.*)") # File name
for x_list in work_list:
key = ''
file_values = []
m1 = re1.match(x_list[0])
if m1:
key = m1.group(2)
# file_values.append(m1.group(1)) # pid name first item in list
for y_strings in x_list:
m2 = re2.match(y_strings)
if m2:
file_values.append(m2.group(1))
pid_dict[key] = file_values
# Make a set of all the open files
values = []
for v in pid_dict.values():
values.extend(v)
files_open = sorted(set(values))
txt_file = os.path.join(os.getenv('TEMP'), 'lsof_handle_files')
with open(txt_file, 'w') as fd:
for a in sorted(files_open):
fd.write(a + '\n')
subprocess.call(['notepad', txt_file])
os.remove(txt_file)
Como se ha dicho anteriormente, se puede enumerar FDS en Linux en /proc/self/fd, aquí es un método simple para enumerar mediante programación:
import os
import sys
import errno
def list_fds():
"""List process currently open FDs and their target """
if sys.platform != 'linux2':
raise NotImplementedError('Unsupported platform: %s' % sys.platform)
ret = {}
base = '/proc/self/fd'
for num in os.listdir(base):
path = None
try:
path = os.readlink(os.path.join(base, num))
except OSError as err:
# Last FD is always the "listdir" one (which may be closed)
if err.errno != errno.ENOENT:
raise
ret[int(num)] = path
return ret
para listar todos los archivos abiertos en de manera multiplataforma, recomendaría psutil.
#!/usr/bin/env python
import psutil
for proc in psutil.process_iter():
print proc.open_files()
La pregunta original restringe implícitamente la operación para el proceso en ejecución, que se puede acceder a través de la clase de proceso de psutil.
proc = psutil.Process()
print proc.open_files()
Por último, tendrá que ejecutar el código utilizando una cuenta con los permisos apropiados para acceder a esta información o puede ver los errores AccessDenied.
Esto solo parece funcionar para archivos basados en disco, no en sockets, fifos, etc. – NeilenMarais
@NeilenMarais: funciona para sockets, vea ejemplos en https://pypi.python.org/pypi/psutil – LetMeSOThat4U
Nuevas versiones de psutil use el nombre 'proc.get_open_files()' – gerardw
Puede usar la siguiente secuencia de comandos. Se basa en Claudiu's answer. Se aborda algunos de los problemas y añade características adicionales:
- imprime un seguimiento de la pila de donde el archivo se abrió
- Imprime en la salida del programa
- apoyo argumento de palabra clave
Aquí está el código y un enlace al gist, que posiblemente esté más actualizado.
"""
Collect stacktraces of where files are opened, and prints them out before the
program exits.
Example
========
monitor.py
----------
from filemonitor import FileMonitor
FileMonitor().patch()
f = open('/bin/ls')
# end of monitor.py
$ python monitor.py
----------------------------------------------------------------------------
path = /bin/ls
> File "monitor.py", line 3, in <module>
> f = open('/bin/ls')
----------------------------------------------------------------------------
Solution modified from:
https://stackoverflow.com/questions/2023608/check-what-files-are-open-in-python
"""
from __future__ import print_function
import __builtin__
import traceback
import atexit
import textwrap
class FileMonitor(object):
def __init__(self, print_only_open=True):
self.openfiles = []
self.oldfile = __builtin__.file
self.oldopen = __builtin__.open
self.do_print_only_open = print_only_open
self.in_use = False
class File(self.oldfile):
def __init__(this, *args, **kwargs):
path = args[0]
self.oldfile.__init__(this, *args, **kwargs)
if self.in_use:
return
self.in_use = True
self.openfiles.append((this, path, this._stack_trace()))
self.in_use = False
def close(this):
self.oldfile.close(this)
def _stack_trace(this):
try:
raise RuntimeError()
except RuntimeError as e:
stack = traceback.extract_stack()[:-2]
return traceback.format_list(stack)
self.File = File
def patch(self):
__builtin__.file = self.File
__builtin__.open = self.File
atexit.register(self.exit_handler)
def unpatch(self):
__builtin__.file = self.oldfile
__builtin__.open = self.oldopen
def exit_handler(self):
indent = ' > '
terminal_width = 80
for file, path, trace in self.openfiles:
if file.closed and self.do_print_only_open:
continue
print("-" * terminal_width)
print(" {} = {}".format('path', path))
lines = ''.join(trace).splitlines()
_updated_lines = []
for l in lines:
ul = textwrap.fill(l,
initial_indent=indent,
subsequent_indent=indent,
width=terminal_width)
_updated_lines.append(ul)
lines = _updated_lines
print('\n'.join(lines))
print("-" * terminal_width)
print()
- 1. Demasiados archivos abiertos en python
- 2. Demasiados archivos abiertos: cuántos están abiertos, lo que son, y cuántos puede la JVM abierta
- 3. Demasiados archivos abiertos con multiprocesamiento.Pool
- 4. ¿Cómo obtener la línea actual de archivos abiertos en python?
- 5. IOException: Demasiados archivos abiertos
- 6. java.net.SocketException: Demasiados archivos abiertos
- 7. Cerrar archivos abiertos usando C#
- 8. Listar todos los archivos abiertos
- 9. Demasiados manejadores de archivos abiertos
- 10. Jetty IOException: Demasiados archivos abiertos
- 11. en iOS/iPhone: "Demasiados archivos abiertos": necesita a la lista de archivos abiertos (como lsof)
- 12. Socket accept - "Demasiados archivos abiertos"
- 13. Demasiados errores archivos abiertos pero lsof muestra un número legal de archivos abiertos
- 14. Demasiados archivos abiertos utilizando child_process
- 15. Notepad ++ muestra archivos abiertos a la izquierda
- 16. php-fpm Demasiados archivos abiertos
- 17. JBoss Demasiados archivos abiertos Error
- 18. Cierre todos los archivos abiertos en ipython
- 19. Error "Demasiados archivos abiertos" en pdflatex
- 20. Guardar archivos abiertos (sesión) en NetBeans
- 21. RecursiveDirectoryIterator lanza UnexpectedValueException en "Demasiados archivos abiertos"
- 22. Cómo abrir archivos abiertos/usados de un proceso en ejecución
- 23. ¿Las clases en Python están en diferentes archivos?
- 24. ¿Qué significan acentos abiertos al intérprete de Python: `num`
- 25. Qué archivos están realmente incluidos al compilar
- 26. socket.accept error 24: Para muchos archivos abiertos
- 27. ¿Cómo buscar todos los archivos abiertos en Eclipse?
- 28. ¿Recuperando qué pestañas están abiertas en Chrome?
- 29. explorador de archivos abiertos utilizando jQuery
- 30. Archivos abiertos de Visual Studio pregunta
Funcionó como un amuleto para mí, ¡gracias por compartir! –
@Claudiu - ¿puede por favor cómo utilizar cerrar todos los archivos abiertos - def closeall (auto): imprimir "### CERRAR Todos los archivos ###" \t oldfile.close (self, (fx para f en archivos abiertos)) openfiles.remove (self, (fx para f en archivos abiertos)) ¿Funcionará perfectamente? – Prakash
Para no prolongar la vida útil de los objetos de archivo (y por lo tanto evitar el cierre automático en los objetos contados de referencia en cpython) es IMO que vale la pena usar un 'weakref.WeakSet' en lugar de' set' simple para 'abrir archivos'. – coldfix