Другой подход к применению RIPEMD в CSV-файле

Я ищу другой подход для применения RIPEMD-160 ко второму столбцу файла CSV.

Вот мой код

awk -F "," -v env_var="$key" '{
    tmp="echo -n \047" $2 env_var "\047 | openssl ripemd160 | cut -f2 -d\047 \047"
    if ( (tmp | getline cksum) > 0 ) {
        $3 = toupper(cksum)
    }
    close(tmp)
    print
}' /test/source.csv > /ziel.csv

Я запускаю его в большом CSV-файле (1Go), это занимает 2 дня, и я получаю только 100Mo, это означает, что мне нужно подождать месяц, чтобы получить все мои новые CSV.

Можете ли вы помочь мне с другой идеей и подходом, чтобы получить мои данные быстрее.

заранее спасибо

3 ответа

Вы можете использовать GNU Parallel, чтобы увеличить скорость вывода, выполнив команду awk параллельно.

cat /test/source.csv | parallel --pipe awk -F "," -v env_var="$key" '{
    tmp="echo -n \047" $2 env_var "\047 | openssl ripemd160 | cut -f2 -d\047 \047"
    if ( (tmp | getline cksum) > 0 ) {
        $3 = toupper(cksum)
    }
    close(tmp)
    print
}' > /ziel.csv

Ваше решение поражает Cygwin там, где оно приносит наибольшую боль: порождает новые программы. Cygwin ужасно медленно в этом.

Вы можете сделать это быстрее, используя все ядра на вашем компьютере, но это все равно будет очень медленным.

Вам нужна программа, которая не запускает другие программы для вычисления суммы RIPEMD. Вот небольшой скрипт Python, который принимает CSV на стандартный ввод и выводит CSV на стандартный вывод со вторым столбцом, замененным суммой RIPEMD.

riper.py:

#!/usr/bin/python                                                                                  

import hashlib
import fileinput
import os

key = os.environ['key']

for line in fileinput.input():
    # Naiive CSV reader - split on ,                                                               
    col = line.rstrip().split(",")
    # Compute RIPEMD on column 2                                                                   
    h = hashlib.new('ripemd160')
    h.update(col[1]+key)
    # Update column 2 with the hexdigext                                                           
    col[1] = h.hexdigest().upper();
    print ','.join(col)

Теперь вы можете запустить:

cat source.csv | key=a python riper.py > ziel.csv

Это все еще будет использовать только одно ядро ​​вашей системы. Использовать все ядра GNU Parallel может помочь. Если в вашей системе пакетов нет GNU Parallel 20161222 или новее, его можно установить как:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

Вам понадобится Perl для запуска GNU Parallel:

key=a
export key
parallel --pipe-part --block -1 -a source.csv -k python riper.py > ziel.csv

Это на лету расколоть source.csv на один блок на ядро ​​ЦП и для каждого блока запустить скрипт python. На моем 8-ядерном процессоре файл обрабатывается в 1 ГБ с 139482000 строк за 300 секунд.

Если вам нужно еще быстрее, вам нужно будет конвертировать riper.py на скомпилированный язык (например, C).

# prepare a batch (to avoir fork from awk)
awk -F "," -v env_var="$key" '
    BEGIN {
       print "if [ -r /tmp/MD160.Result ];then rm /tmp/MD160.Result;fi"
       }
    {
    print "echo \"\$( echo -n \047" $2 env_var "\047 | openssl ripemd160 )\" >> /tmp/MD160.Result"
    } ' /test/source.csv > /tmp/MD160.eval

# eval the MD for each line with batch fork (should be faster)
. /tmp/MD160.eval

# take result and adapt for output
awk '
   # load MD160
   FNR == NR { m[NR] = toupper($2); next }
   # set FS to ","
   FNR == 1 { FS = ","; $0 = $0 "" }
   # adapt original line
   { $3 = m[FNR]; print}
   ' /tmp/MD160.Result /test/source.csv   > /ziel.csv

Замечания:

  • не тестировался (так что для печати нужно, возможно, некоторую настройку с побегом)
  • нет обработки ошибок (предположим, что все в порядке). Я советую сделать некоторые проверки (например, включить ссылку на строку в ответ и проверить во втором awk).
  • fork на уровне пакета будет намного быстрее, чем fork из awk, включая конвейерную вилку, перехватывая ответ
  • не специалист по openssl maturemd160, но, возможно, есть другой способ обработки элемента в массовом процессе, не открывая каждый раз форк из того же файла / источника
Другие вопросы по тегам