2010-01-29 29 views
9

Tengo un código que estoy usando para buscar los ejecutables de los archivos del juego y devolver los directorios. Realmente me gustaría obtener algún tipo de indicador de progreso en cuanto a qué tan avanzado está os.walk. ¿Cómo lograría tal cosa?¿Cómo obtener el progreso de os.walk en python?

Intenté hacer startpt = root.count(os.sep) y medirlo, pero eso solo da qué tan profundo os.walk está en un árbol de directorios.

def locate(filelist, root=os.curdir): #Find a list of files, return directories. 
    for path, dirs, files in os.walk(os.path.abspath(root)): 
     for filename in returnMatches(filelist, [k.lower() for k in files]): 
      yield path + "\\" 
+0

la verdadera pregunta es por qué su 'os.walk' tarda tanto tiempo? ¿Cuantos archivos estás tecleando? ¿Cuál es el rendimiento de 'returnMatches'? – SilentGhost

+0

def returnMatches (a, b): lista de devolución (set (a) & set (b)) # Devuelve una lista, de coincidencias entre las listas dadas. Eso es todo returnMatches es ... esto solo toma un par de segundos para completarse pero estoy agregando polaco al programa así que a las personas no parece que mi programa simplemente no haga nada por un par de segundos. En la máquina * MY * todo tarda unos 10 segundos en completarse. Pero esto se va a empaquetar y ejecutar en cualquier cantidad de máquinas/entornos de Windows. – ThantiK

+0

Nota sobre mi máquina: sigue ejecutando una unidad IDE muy lenta. ;) – ThantiK

Respuesta

3

Me di cuenta de esto.

que utilizan os.listdir para obtener una lista de directorios de nivel superior, y luego utiliza la función .split en el camino que os.walk regresó, volviendo el primer directorio de nivel que era actualmente.

que dejó con una lista de directorios de nivel superior, que pude encontrar el índice del directorio actual de os.walk, y comparar el índice devuelto con la longitud de la lista, dándome un% completado. ;)

Esto no me da un progreso liso, porque el nivel de trabajo realizado en cada directorio puede variar, pero suavizar el indicador de progreso no me concierne. Pero podría lograrse fácilmente extendiendo la ruta comprobando más profundamente en la estructura del directorio.

Aquí es el código final de conseguir mi progreso:

def locateGameDirs(filelist, root=os.curdir): #Find a list of files, return directories. 
    toplevel = [folder for folder in os.listdir(root) if os.path.isdir(os.path.join(root, folder))] #List of top-level directories 
    fileset = set(filelist) 

    for path, dirs, files in os.walk(os.path.abspath(root)): 

     curdir = path.split('\\')[1] #The directory os.walk is currently in. 

     try: #Thrown here because there's a nonexistant(?) first entry. 
      youarehere = toplevel.index(curdir) 
      progress = int(((youarehere)/len(toplevel))*100) 
     except: 
      pass 

     for filename in returnMatches(filelist, [k.lower() for k in files]): 
      yield filename, path + "\\", progress 

Y en este momento para fines de depuración que estoy haciendo esto más adelante en el código:

for wow in locateGameDirs(["wow.exe", "firefox.exe", "vlc.exe"], "C:\\"): 
    print wow 

¿Hay un poco más agradable para deshacerse de ese intento/excepto ?; parece que la primera iteración de ruta no me da nada ...

+0

La primera iteración le proporciona la raíz. Prueba agregar "ruta de impresión" para ver a qué me refiero. –

2

hacerlo en dos pasos: en primer lugar contar cuántas Total de archivos/carpetas están en el árbol, y luego durante la segunda pasada hacer el proceso real.

+0

¿No tomaría esto el doble? –

+1

Eso solo es útil si el procesamiento lleva mucho más tiempo que hacerlo. Si el OP abre cada archivo, probablemente lo haga. Si el OP solo está mirando algún detalle del nombre, es casi seguro que no. – Omnifarious

+0

@Omnifarious: entonces no está claro por qué querría saber el progreso, ya que costará más que el procesamiento real. – SilentGhost

0

Necesita saber la cantidad total de archivos para hacer un indicador de progreso significativo.
Usted puede obtener el número de archivos como éste

len(list(os.walk(os.path.abspath(root)))) 

sino que va a tomar algún tiempo y es probable que tenga un indicador de progreso para que ...

Para encontrar el número de archivos muy rápido necesitarías un sistema de archivos que haga un seguimiento de la cantidad de archivos para ti.

Tal vez se puede guardar el total a partir de una ejecución anterior y usar eso como una estimación

+1

No me importa la cantidad de archivos. Honestamente, me gustaría saber en qué directorio superior se encuentra en todos los directorios principales. Por ejemplo, tengo directorios principales llamados C: \\ 1, C: \\ 2, y así sucesivamente ... Solo diciendo 'Tu en el directorio de alto nivel x de x' estaría bien, simplemente no lo hago Saber cómo llevarlo a cabo. – ThantiK

+0

Lo resolví al menos para obtener mis directorios de nivel superior: [carpeta para la carpeta en os.listdir ('C: \\') si os.path.isdir (os.path.join ('C: \\ ', carpeta))] Ahora, ¿cómo podría averiguar dónde está os.walk? – ThantiK

5

Depende!

Si los archivos y directorios se distribuyen de forma más o menos uniforme, podría mostrar el proceso aproximado suponiendo que cada uno de los directorios de nivel superior tardará la misma cantidad de tiempo. Pero si no se distribuyen de manera uniforme no se puede averiguar a bajo costo. O bien debe saber de forma aproximada qué tan ocupado está cada directorio por adelantado, o debe hacerlo todo el tiempo dos veces (pero eso solo es útil si su procesamiento real lleva mucho más tiempo que el propio os.walk).

Esto es: supongamos que tiene 4 directorios de nivel superior, y cada uno contiene 4 archivos. Si supone que cada uno de los directorios toplevel toma el 25% del progreso, y cada archivo toma otro 25% del progreso de ese directorio, puede mostrar un buen indicador de progreso. Pero si el último subdirector contiene muchos más archivos que los primeros, su indicador de progreso habrá alcanzado el 75% antes de que lo descubra. Realmente no se puede arreglar si el os.walk en sí mismo es el cuello de botella (no su procesamiento) y es un árbol de directorios arbitrario (no uno en el que se sabe por adelantado aproximadamente cuánto tiempo tomará cada subárbol).

Y, por supuesto, esto es suponiendo que el costo aquí es aproximadamente la misma para cada archivo ...

4

Solo tiene que mostrar una barra de progreso indeterminada (es decir, las que muestran una mancha rebotando o el efecto del peluquero) . De esa forma, los usuarios saben que el programa está haciendo algo útil, pero no los engaña en cuanto al tiempo para completarlos, etc.

+0

Aunque descubrí mi problema, ya que la operación es tan corta, probablemente tenga razón en esto. Gracias;) – ThantiK

0

Le sugiero que evite caminar por el directorio. En su lugar, use una aplicación indexada para encontrar rápidamente los archivos. Puede usar la interfaz de línea de comandos de la aplicación a través de un subproceso y buscar los archivos casi instantáneamente.

En Windows, vea Everything. En UNIX, mira localizar. No estoy seguro acerca de Mac, pero estoy seguro de que hay una opción allí también.

+0

Este va a ser un ejecutable empaquetado que se distribuirá a las personas. No para uso personal No puedo estar usando cosas como esta. – ThantiK

+0

¿No podría enviar la aplicación de búsqueda junto con su programa? Posiblemente ayudado por un instalador? Si realmente quiere caminar, las únicas opciones que veo ya han sido sugeridas: hacer dos caminatas (una para contar, una para la operación real), o una barra de progreso indeterminada que marca después de cada x número de iteraciones. –

+0

No. El programa es básicamente un solo ejecutable de 4MB empaquetado con py2exe, no hay razón para instalar un programa que solo busca una lista de juegos instalados y carga los archivos guardados del juego en un servidor. – ThantiK

0

Como dije en el comentario, el cuello de la botella de rendimiento probablemente se encuentre fuera de la función locate. su returnMatches es una función bastante costosa.Creo que sería mejor de su sustitución por el siguiente código:

def locate(filelist, root=os.curdir) 
    fileset = set(filelist)   # if possible, pass the set instead of the list as a first argument 
    for path, dirs, files in os.walk(os.path.abspath(root)): 
      if any(file.lower() in fileset for file in files): 
       yield path + '\\' 

De esta manera se reduce el número de operaciones de despilfarro, el rendimiento de una vez por archivo en el directorio (que creo que es lo que realmente sangría que hacer) y puedes olvidarte del progreso al mismo tiempo. No creo que el progreso sea una característica esperada de la interfaz de todos modos.

+0

def returnMatches (a, b): lista de devolución (set (a) & set (b)) Y probé su método publicado aquí. No funcionó más rápido. – ThantiK

+0

@ThantiK: solo significa que la mayor parte del tiempo lo gasta 'os.walk'. No hace que tu enfoque sea eficiente. – SilentGhost

0

Pensando fuera de la caja aquí ... lo que si lo hizo basado en tamaño:

  • Uso subproceso ejecutar 'du -sb' y obtener la TOTAL_SIZE de la raíz directorio
  • al caminar, comprobar el tamaño de cada archivo y decremento de su TOTAL_SIZE (que le da remaining_size)
  • pct_complete = (TOTAL_SIZE - remaining_size)/TOTAL_SIZE

¿Pensamientos?

-aj

0

Una optimización que podría hacer: está convirtiendo la lista de archivos en un conjunto en cada llamada a returnMatches, aunque nunca cambia. mover la conversión al inicio de la función 'localizar' y pasar el conjunto en cada iteración.

+0

Gracias - De hecho tomé esto de la publicación de SilentGhosts, a pesar de que le preocupaba más el rendimiento que la tarea en cuestión;) – ThantiK

0

Bueno, esto fue divertido. Aquí hay otra manera tonta de hacerlo, pero como todo lo demás, solo calcula el progreso correcto para caminos uniformes.

import os, sys, time 

def calc_progress(progress, root, dirs): 
    prog_start, prog_end, prog_slice = 0.0, 1.0, 1.0 

    current_progress = 0.0 
    parent_path, current_name = os.path.split(root) 
    data = progress.get(parent_path) 
    if data: 
     prog_start, prog_end, subdirs = data 
     i = subdirs.index(current_name) 
     prog_slice = (prog_end - prog_start)/len(subdirs) 
     current_progress = prog_slice * i + prog_start 

     if i == (len(subdirs) - 1): 
      del progress[parent_path] 

    if dirs: 
     progress[root] = (current_progress, current_progress+prog_slice, dirs) 

    return current_progress 

def walk(start_root): 
    progress = {} 
    print 'Starting with {start_root}'.format(**locals()) 

    for root, dirs, files in os.walk(start_root): 
     print '{0}: {1:%}'.format(root[len(start_root)+1:], calc_progress(progress, root, dirs)) 
Cuestiones relacionadas