вложение GNU Parallel для обработки нескольких огромных файлов и разделения данных каждого файла для обработки в виде очереди

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

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

# 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 = []; 
    }
}

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

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

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

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

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

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

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

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

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

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

Любая идея, как это можно сделать лучше?


person Waku-2    schedule 25.10.2018    source источник
comment
Вы, конечно, имеете в виду json_encode()?   -  person Mark Setchell    schedule 02.11.2018


Ответы (1)


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

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 не займет много времени, то последний может быть предпочтительнее, потому что он будет распределяться более равномерно, если файлы очень разных размеров, поэтому, если последний файл большой, вам не придется ждать одиночного процесс, чтобы закончить обработку этого.

person Ole Tange    schedule 25.10.2018