О, это ты. Проходи, садись поближе к системному блоку, тут тепло. Настало время приступить ко второй части (не пропусти и первую часть тоже) наших исследований и понабирать еще зеленоватых буковок на черном экране. Сегодня будет настоящий хардкор, мы привлечем все наши знания, чтобы составить действительно сложные и почти нечитаемые команды, с помощью которых перепашем кучу данных в параллельном режиме.

 

Нужно больше крестьян

Мы запомнили множество команд, освоили grep и awk и разобрались, как обходить подводные камни, но еще не можем сказать, что заставляем комп работать на все сто процентов. Однако это легко исправить, если всего лишь научиться использовать несколько ядер процессора и, например (один из стандартных подходов), создать очередь для параллельной обработки данных воркерами.

Не надо напрягаться, я не буду сейчас рассказывать про тонкости многопоточного программирования и примитивы синхронизации. Мы же договорились, что все будет в консоли, — так и поступим. А поможет в этом квесте, как ни странно, еще одна стандартная утилита командной строки, про которую ты наверняка слышал, — xargs. Да, ее основная задача — это подставлять результат выполнения одной команды в качестве аргумента другой, но этим ее возможности не исчерпываются. Освежим память:

$ find . -name "*.sh" -print0 | xargs -0 -I'{}' mv '{}' ~/backup_scripts

Здесь все просто: находим в текущем каталоге все файлы с расширением .sh и скармливаем их поочередно команде mv, которая швыряет их в бэкап. Ключи -print0 и -0 здесь указывают на то, что данные, поступающие из выхода find на вход в xargs, будут по-сишному разделены null-байтом. Параметр -I, в свою очередь, задает шаблон, который будет использоваться при подстановке значений в управляемую команду.

Казалось бы, при чем здесь очередь сообщений и воркеры? Сейчас это просто обычный цикл, в котором на каждой итерации команда mv что-то куда-то копирует. А хитрость вот в чем: никто не говорил, что xargs умеет и обязан запускать ровно один экземпляр команды. Представим, например, такую структуру каталогов (да, это вывод еще одной полезной консольной команды):

Что получится, если мы запустим такую (абсолютно бесполезную, но все же) команду?

$ ls | xargs -P3 -n1 ls

Или (а это даже интереснее) что будет, если мы запустим ее несколько раз?

$ ls | xargs -P3 -n1 ls
pikachu.avi
1_bar.txt  1_foo.txt
unforgivable_pics.zip

$ ls | xargs -P3 -n1 ls
1_bar.txt  1_foo.txt
pikachu.avi
unforgivable_pics.zip

Что-то эта ситуация напоминает, не правда ли? Несколько независимых процессов, пишущих в одну консоль, например? Да-да, параметр -P здесь задает количество процессов для запуска (можно поставить число ядер процессора, например ;)), а -n указывает, сколько строк из входа одновременно передавать каждому процессу. В результате запускается не один, а сразу три экземпляра команды ls, каждый из которых начинает разбирать строчки из очереди, организованной xargs. Кто первый встал — того и тапки, причем команда не завершается, пока не отработает последний воркер, то есть барьер здесь тоже есть.

Дальше — больше. Понадобилось мне как-то скопировать приличное количество файлов с HDFS. Делать это в большом цикле — очень долго, писать навороченные скрипты специально для этой задачи — как-то уныло. В итоге через несколько минут появилось вот такое детище Франкенштейна:

$ cat file.txt | xargs -l bash -c 'echo hdfs dfs -get $0 $1' | xargs -I {} -d '\n' -n1 -P8 -t bash -c "eval {}"

Сейчас объясню. На входе был файл, в котором на каждой строчке два пути — адрес файла внутри HDFS и место, куда его надо скопировать локально. Чтобы скопировать данные быстро, необходимо было запустить операции копирования в несколько потоков. Первый вызов xargs превращает поток из пар адресов в поток команд по копированию данных (file1 file2 становится echo hdfs dfs -get file1 file2), также разделенных переносом строки (-d во втором xargs как раз для обработки такого случая). После этого поток передается второму xargs, который выполняет сформированные на предыдущем шаге команды в восемь потоков. Громоздко? Да, можно так сказать. Но на отлично решает задачу и сильно экономит время.

Есть еще одна команда, специально для параллелизации, с довольно неожиданным названием

Продолжение статьи доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи одну статью

Заинтересовала статья, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для статей, опубликованных более двух месяцев назад.


Комментарии

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

Как сделать игру. Выбираем движок и пишем клон тех самых «танчиков»

С каждым днем игры становятся все сложнее и навороченнее. Быть инди, а точнее соло-разрабо…