2011-03-29 6 views
5

Tenemos archivos bastante grandes, del orden de 1-1.5 GB combinados (principalmente archivos de registro) con datos brutos que son fácilmente analizables por un csv, que posteriormente se supone que se grafica para generar un conjunto de imágenes gráficas.Leer y graficar datos leídos desde archivos enormes

Actualmente, estamos utilizando los scripts bash para convertir los datos brutos en un archivo csv, con solo los números que deben graficarse, y luego alimentarlo en un script gnuplot. Pero este proceso es extremadamente lento. Traté de acelerar los scripts bash reemplazando algunos cut s, tr s con un solo comando awk, aunque esto mejoró la velocidad, todo sigue siendo muy lento.

Por lo tanto, estoy empezando a creer que hay mejores herramientas para este proceso. Actualmente estoy buscando reescribir este proceso en python + numpy o R. Un amigo mío sugirió usar JVM, y si tengo que hacerlo, usaré clojure, pero no estoy seguro de cómo funcionará la JVM.

No tengo mucha experiencia en este tipo de problemas, por lo que cualquier consejo sobre cómo proceder sería genial. Gracias.

Edit: Además, querré almacenar (en el disco) los datos intermedios generados, es decir, el csv, así que no tengo que volver a generarlo, debería elegir Quiero un gráfico de aspecto diferente .

Editar 2: Los archivos de datos brutos tienen un registro por línea, cuyos campos están separados por un delimitador (|). No todos los campos son números. Cada campo que necesito en la salida csv se obtiene aplicando una determinada fórmula en los registros de entrada, que pueden usar múltiples campos de los datos de entrada. La salida csv tendrá 3-4 campos por línea, y necesito gráficos que tracen 1-2, 1-3, 1-4 campos en un (puede ser) gráfico de barras. Espero que eso dé una mejor imagen.

Editar 3: He modificado un poco la secuencia de comandos de @ adirau y parece estar funcionando bastante bien. He avanzado lo suficiente como para leer datos, enviarlos a un grupo de subprocesos de procesador (pseudoproceso, anexar nombre de subproceso a datos) y agregarlos en un archivo de salida a través de otro hilo colector.

PD: No estoy seguro del etiquetado de esta pregunta, no dude en corregirlo.

+0

Con archivos de ese tamaño, R puede ser complicado, ya que requiere bastante memoria. Sin embargo, las posibilidades gráficas de R exceden las de Python (ver, por ejemplo, http://addictedtor.free.fr/graphiques/). Asegúrese de verificar el multihilo en R (paquete de nieve). Pero sobre todo, codifique con lo que está familiarizado. Si no está muy familiarizado con R, será difícil optimizar esto. –

+0

sí, ese es otro punto, tengo poca o ninguna experiencia en R, y lo mismo con numpy y matplotlib, pero estoy muy cómodo con python. Esto también influirá en mi elección. –

Respuesta

4

python suena como una buena opción porque tiene una buena API de subprocesos (aunque la implementación es cuestionable), matplotlib y pylab. Echo de menos algunas especificaciones de tu parte, pero quizás este sea un buen punto de partida para ti: matplotlib: async plotting with threads. Buscaría un hilo único para manejar las lecturas de E/S de disco masivo y sincronizar las colas en un grupo de subprocesos para el procesamiento de datos (si ha fijado longitudes de registro, las cosas pueden volverse más rápidas precomputando compensaciones de lectura y pasando solo las compensaciones al subproceso); con el hilo diskio, mmap los archivos de origen de datos, leo un número numérico predefinido + una lectura más para eventualmente tomar los últimos bytes hasta el final de la entrada de línea del origen de datos actual; los numbytes deben elegirse en algún lugar cerca de la longitud promedio de entrada de línea; el siguiente es la alimentación en grupo a través de la cola y el procesamiento/trazado de datos que tiene lugar en el grupo de hilos; No tengo una buena imagen aquí (de qué estás tramando exactamente) pero espero que esto ayude.

EDITAR: hay archivo.readlines ([sizehint]) para tomar múltiples líneas a la vez; así que puede no ser tan rápida primo los documentos están diciendo su usando readline() internamente

EDIT: un código esqueleto rápida

import threading 
from collections import deque 
import sys 
import mmap 


class processor(Thread): 
    """ 
     processor gets a batch of data at time from the diskio thread 
    """ 
    def __init__(self,q): 
     Thread.__init__(self,name="plotter") 
     self._queue = q 
    def run(self): 
     #get batched data 
     while True: 
      #we wait for a batch 
      dataloop = self.feed(self._queue.get()) 
      try: 
       while True: 
        self.plot(dataloop.next()) 
      except StopIteration: 
       pass 
      #sanitizer exceptions following, maybe 

    def parseline(self,line): 
     """ return a data struct ready for plotting """ 
     raise NotImplementedError 

    def feed(self,databuf): 
     #we yield one-at-time datastruct ready-to-go for plotting 
     for line in databuf: 
      yield self.parseline(line) 

    def plot(self,data): 
     """integrate 
     https://www.esclab.tw/wiki/index.php/Matplotlib#Asynchronous_plotting_with_threads 
     maybe 
     """ 
class sharedq(object): 
    """i dont recall where i got this implementation from 
    you may write a better one""" 
    def __init__(self,maxsize=8192): 
     self.queue = deque() 
     self.barrier = threading.RLock() 
     self.read_c = threading.Condition(self.barrier) 
     self.write_c = threading.Condition(self.barrier) 
     self.msz = maxsize 
    def put(self,item): 
     self.barrier.acquire() 
     while len(self.queue) >= self.msz: 
      self.write_c.wait() 
     self.queue.append(item) 
     self.read_c.notify() 
     self.barrier.release() 
    def get(self): 
     self.barrier.acquire() 
     while not self.queue: 
      self.read_c.wait() 
     item = self.queue.popleft() 
     self.write_c.notify() 
     self.barrier.release() 
     return item 



q = sharedq() 
#sizehint for readine lines 
numbytes=1024 
for i in xrange(8): 
    p = processor(q) 
    p.start() 
for fn in sys.argv[1:] 
    with open(fn, "r+b") as f: 
     #you may want a better sizehint here 
     map = mmap.mmap(f.fileno(), 0) 
     #insert a loop here, i forgot 
     q.put(map.readlines(numbytes)) 

#some cleanup code may be desirable 
+0

Gracias por sus ideas adirau, mi intención al usar python fue para poder usar hilos agrupados que leen los datos de una cola. En cuanto a una mejor imagen, edité la pregunta con más información, espero que dé una mejor idea de lo que estoy haciendo. –

+0

Muchas gracias por el código adirou, me tomó un tiempo pasar ya que nunca he usado 'deque' y' mmap'. ¿Podría señalar más información sobre esos, también cuál es la diferencia entre 'queue.Queue' y' deque'? y ¿por qué no abrir el archivo de forma simple y leer líneas secuencialmente? –

+0

Se supone que collections.deque ofrece operaciones atómicas rápidas anexadas y popleft que no requieren bloqueo (recorte de la documentación de la cola); puedes encontrar documentos deque y mmap en la documentación de Python; Opté por las lecturas de líneas masivas como una especie de optimización rápida; las líneas de lectura y colas, una por una, parecían una mala idea (más llamadas de línea de lectura, más operaciones de cola), así que pensé que era mejor y más rápido para leer a granel y procesar a granel; – user237419

1

Creo pitón + Numpy sería la forma más eficiente, en cuanto a velocidad y facilidad de implementación. Numpy está altamente optimizado, por lo que el rendimiento es aceptable, y python facilitaría la parte de implementación del algoritmo.

Este combo debería funcionar bien para su caso, siempre que optimice la carga del archivo en memoria, trate de encontrar el punto medio entre procesar un bloque de datos que no sea demasiado grande pero lo suficientemente grande como para minimizar la lectura y escritura ciclos, porque esto es lo que ralentizará el programa

Si siente que esto necesita más aceleración (que sinceramente dudo), podría usar Cython para acelerar las partes inactivas.

+0

No terminé de obtener su segundo párrafo, ¿es que si hago '.read (2000) .splitlines()', funcionará mejor que haciendo '.readline()' para cada línea? –

+0

Aconsejo que, dado que minimizaría los ciclos de lectura y escritura, una vez más debe encontrar el tamaño óptimo según su configuración, otra cosa acerca de ** readline() ** es que puede causarle errores, ya que se lee algunas veces las líneas en un orden diferente que en el archivo leído, especialmente cuando se mezcla iteración de archivo con readline – P2bM

Cuestiones relacionadas