Bashscript с параллельной операцией curl

У меня есть список с URL-адресами, которые мне нравится загружать с помощью CURL и выполнять некоторые операции с результатом с помощью сценария bash. Поскольку это почти 100 тысяч запросов, мне нравится запускать их параллельно. Я уже изучил параллели GNU, но как мне склеить все вместе? Спасибо!

Башскрипт:

while read URL; do
curl -L -H "Accept: application/unixref+xml" $URL > temp.xml;

YEAR=$(xmllint --xpath '//year' temp.xml);
MONTH=$(xmllint --xpath '(//date/month)[1]' temp.xml);

echo "$URL;$YEAR;$MONTH" >> results.csv;

sed -i '1d' urls.txt;

done < urls.txt;

person Thomas    schedule 15.11.2013    source источник
comment
Я бы не стал изменять urls.txt внутри цикла при чтении из него. В лучшем случае это кажется ненужным.   -  person chepner    schedule 15.11.2013


Ответы (1)


Вы не должны изменять входной список URL-адресов при выполнении каждого HTTP-запроса. И наличие нескольких приложений, записывающих в один и тот же выходной файл из разных процессов, скорее всего, закончится плачевно.

Поместите большинство ваших команд в отдельный скрипт (скажем, с именем geturl.sh), который можно будет вызывать с URL-адресом в качестве параметра, и записывает свою строку вывода в стандартный вывод:

#!/usr/bin/env bash
URL="${1}"
curl -L -H "Accept: application/unixref+xml" "${URL}" > /tmp/$$.xml
YEAR="$(xmllint --xpath '//year' /tmp/.xml)"
MONTH="$(xmllint --xpath '(//date/month)[1]' /tmp/$$.xml)"
rm -f /tmp/$$.xml
echo "${URL};${YEAR};${MONTH}"

Затем вызовите следующим образом (здесь мы позволяем parallel объединять выходные данные из различных потоков построчно):

parallel --line-buffer geturl.sh < urls.txt > results.csv
person pobrelkey    schedule 15.11.2013
comment
Спасибо, это работает. Я провел тестовый запуск для 100 URL-адресов, но похоже, что он работает не лучше, чем серийная версия. Может быть проблема в скручивании? Я запускаю CygWin - person Thomas; 16.11.2013
comment
Попробуйте запустить еще несколько заданий параллельно: parallel -j100 Также имейте в виду, что --line-buffer работает намного медленнее, чем по умолчанию (буферизация полного задания за раз). - person Ole Tange; 16.11.2013
comment
Благодаря добавлению -j100 производительность улучшается. Есть ли альтернатива --line-buffer? - person Thomas; 16.11.2013
comment
Не уверен, что вам даже нужно --line-buffer - я добавил это из-за предосторожности. - person pobrelkey; 16.11.2013
comment
Я запускал параллель без --line-buffer, и он все еще работает, хотя и не ускоряет процесс. Я провел несколько тестов, и не имеет значения, выбираю ли я -j100 или -j5, для запуска всей партии всегда требуется 6 минут, нельзя ли это улучшить? Или загрузка URL-адресов является узким местом? К сожалению, я не могу запустить многопоточный Curl в CygWIn. - person Thomas; 16.11.2013
comment
Ой, сигвин. Процессы порождения дороже на cygwin, чем на реальном unix. Может ли двукратный вызов утилиты синтаксического анализа XML для каждого файла быть частью накладных расходов? Кроме того, вы можете попробовать реструктурировать свои сценарии, чтобы curl извлекало множество URL-адресов за одно выполнение (используйте split, чтобы разбить список URL-адресов). Но лучшим подходом, вероятно, было бы написать сценарий perl/python/ruby, который загружает и анализирует XML-файлы внутри сценария, и разделяет вашу работу на несколько одновременных запусков этого. - person pobrelkey; 16.11.2013