Вложение GNU Parallel для обработки нескольких огромных файлов и разделения каждого файла данных для обработки в виде очереди - PullRequest
0 голосов
/ 25 октября 2018

У меня есть каталог с почти 100 файлами журналов, каждый весом 10 ~ 15 ГБ.Требуется построчно читать каждый файл (порядок не имеет значения), очищать строку json и выгружать ее в хранилище внутреннего упругого поиска для индексации.

вот мой работник, который выполняет эту работу

# file = worker.php

echo " -- New PHP Worker Started -- "; // to get how many times gnu-parallel initiated the worker
$dataSet = [];

while (false !== ($line = fgets(STDIN))) {

    // convert line text to json
    $l = json_decode($line);
    $dataSet[] = $l;

    if(sizeof($dataSet) >= 1000) {
        //index json to elasticsearch
        $elasticsearch->bulkIndex($dataSet);
        $dataSet = []; 
    }
}

С помощью ответов здесь и здесь Я почти там, и он работает (вроде), но просто нужно убедиться, что подНа самом деле, он делает то, что, как я предполагаю, делает.

С одним файлом я могу справиться, как показано ниже

parallel --pipepart -a 10GB_input_file.txt  --round-robin php worker.php 

Это прекрасно работает.добавление --round-robin гарантирует, что рабочий процесс php запускается только один раз, а затем просто продолжает получать данные в виде конвейера (очередь плохого человека).

Таким образом, для машины 4CPU он запускает 4 рабочих php иочень быстро обрабатывает все данные.

Чтобы сделать то же самое для всех файлов, вот мое мнение

find /data/directory -maxdepth 1 -type f | parallel cat | parallel --pipe -N10000 --round-robin php worker.php 

Что-то вроде работает, но у меня есть ощущение, что этонеправильный способ вложения параллели для всех файлов.

А во-вторых, поскольку он не может использовать --pipepart, я думаю, что он медленнее.

В-третьих, как только работа завершена, я вижучто на 4cpu машине, только 4 рабочих были запущены, и работа была выполнена.Это правильное поведение?Разве это не должно запускать 4 рабочих для каждого файла?Просто хочу убедиться, что я не пропустил никаких данных.

Есть идеи, как это можно сделать лучше?

1 Ответ

0 голосов
/ 25 октября 2018

Если они примерно одинакового размера, почему бы просто не дать один файл каждому:

find /data/directory -maxdepth 1 -type f |
  parallel php worker.php '<' {}

Другой способ - использовать --pipepart для каждого из них:

do_one() {
  parallel --pipepart -a "$1" --block -1 php worker.php
}
export -f do_one
find /data/directory -maxdepth 1 -type f | parallel -j1 do_one

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

...