Чтение и построение графиков данных, прочитанных из огромных файлов - PullRequest
5 голосов
/ 29 марта 2011

У нас есть довольно большие файлы, порядка 1-1,5 ГБ, объединенные (в основном, файлы журналов) с необработанными данными, которые легко разбираются в CSV, который впоследствии предполагается построить для создания набора графических изображений.

В настоящее время мы используем сценарии bash, чтобы превратить необработанные данные в файл csv, содержащие только цифры, которые необходимо отобразить, а затем передать их в сценарий gnuplot. Но этот процесс очень медленный. Я попытался ускорить выполнение сценариев bash, заменив некоторые переданные по каналу cut s, tr s и т. Д. Одной командой awk, хотя это улучшило скорость, но все еще очень медленно.

Итак, я начинаю верить, что есть лучшие инструменты для этого процесса. В настоящее время я хочу переписать этот процесс на python + numpy или R. Мой друг предложил использовать JVM, и если я собираюсь это сделать, я буду использовать clojure, но не уверен, как будет работать JVM.

У меня нет большого опыта в решении подобных проблем, поэтому любой совет о том, как действовать, был бы полезен. Благодаря.

Редактировать: Кроме того, я хочу сохранить (на диск) сгенерированные промежуточные данные, т.е. CSV, поэтому мне не нужно повторно генерировать их, если я выберу, я хочу другой выглядящий график.

Редактировать 2: Файлы необработанных данных имеют одну запись на одну строку, поля которой разделены разделителем (|). Не все поля являются числами. Каждое поле, которое мне нужно в выходных csv, получается путем применения определенной формулы к входным записям, которая может использовать несколько полей из входных данных. Выходной CSV будет иметь 3-4 поля на строку, и мне нужны графики, которые отображают 1-2, 1-3, 1-4 поля на (может быть) гистограмме. Я надеюсь, что это дает лучшую картину.

Редактировать 3: Я немного изменил скрипт @ adirau, и, похоже, он работает довольно хорошо. Я пришел достаточно далеко, чтобы прочитать данные, отправить их в пул потоков процессора (псевдообработка, добавить имя потока к данным) и объединить их в выходной файл через другой поток collector .

PS: я не уверен насчет пометки этого вопроса, не стесняйтесь исправить его.

Ответы [ 2 ]

4 голосов
/ 29 марта 2011
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Питон, который звучит

, является хорошим выбором, потому что у него хороший API потоков (хотя реализация сомнительна), matplotlib и pylab. Я скучаю по некоторым спецификациям с твоего конца, но, возможно, это может быть хорошей отправной точкой для тебя: matplotlib: асинхронное построение с потоками . Я бы выбрал один поток для обработки массовых операций чтения / вывода с диска и синхронизации очередей с пулом потоков для обработки данных (если у вас фиксированная длина записи, все может быть быстрее, если предварительно вычислить смещения чтения и передать только смещения в пул потоков) ; с дисковым потоком я бы отобразил файлы источника данных, прочитал заранее определенное число байтов + еще одно чтение, чтобы в конце концов захватить последние байты до конца текущего ввода строки источника данных; numbytes следует выбирать где-то рядом со средней длиной строки ввода; затем идет подача пула через очередь и обработка / построение данных в пуле потоков; У меня нет хорошей картины здесь (о том, что именно вы планируете), но я надеюсь, что это поможет.

РЕДАКТИРОВАТЬ: есть file.readlines ([sizehint]) для захвата нескольких строк одновременно; ну, это может быть не так быстро, потому что документы говорят, что он использует readline () внутри

РЕДАКТИРОВАТЬ: быстрый код скелета

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
1 голос
/ 29 марта 2011

Я думаю, что Python + Numpy будет наиболее эффективным способом, с точки зрения скорости и простоты реализации. Numpy высоко оптимизирован, поэтому производительность приличная, а python упростит часть реализации алгоритма.

Эта комбинация должна хорошо работать в вашем случае, если вы оптимизируете загрузку файла в память, пытаетесь найти среднюю точку между обработкой блока данных, который не слишком большой, но достаточно большой, чтобы минимизировать циклы чтения и записи , потому что это то, что замедлит программу

Если вы чувствуете, что это требует более быстрого ускорения (в чем я искренне сомневаюсь), вы можете использовать Cython для ускорения вялых частей.

...