Параллельная загрузка с использованием утилиты командной строки Curl

Я думаю, что было бы полезно сослаться на ответ, объясняющий это тоже. Это о boost::compressed_pair на Логан Капальдо .

23
задан Ravi Gupta 26 December 2011 в 08:31
поделиться

3 ответа

Мой ответ немного запоздалый, но я считаю, что все существующие ответы немного не соответствуют действительности. Я делаю подобные вещи с помощью xargs, который способен запускать определенное количество команд в подпроцессах.

Я бы использовал одну строчку, просто:

$ seq 1 10 | xargs -n1 -P2 bash -c 'i=[110]; url="http://example.com/?page${i}.html"; curl -O -s $url'

Это требует некоторого объяснения. Использование -n 1 инструктирует xargs обрабатывать один входной аргумент за раз. В этом примере числа 1 ... 10 обрабатываются отдельно. И -P 2 говорит xargs, чтобы все 2 подпроцесса работали постоянно, каждый из которых обрабатывал один аргумент, пока все входные аргументы не были обработаны.

Вы можете думать об этом как о MapReduce в оболочке. Или, может быть, только фаза карты. Независимо от этого, это эффективный способ выполнить большую работу, гарантируя, что вы не разбомбите свою машину. Можно сделать что-то похожее в цикле for в оболочке, но в итоге вы будете выполнять управление процессами, которое начинает казаться довольно бессмысленным, когда вы поймете, насколько безумно велико это использование xargs.

Обновление: я подозреваю, что мой пример с xargs мог бы быть улучшен (по крайней мере, в Mac OS X и BSD с флагом -J). С GNU Parallel команда также немного менее громоздкая:

parallel --jobs 2 curl -O -s http://example.com/?page{}.html ::: {1..10}
39
ответ дан ndronen 26 December 2011 в 08:31
поделиться

Для запуска параллельных команд, почему бы не использовать уважаемую утилиту командной строки make. Она поддерживает параллельное выполнение, отслеживание зависимостей и еще много чего.

Как? В каталоге, в который вы загружаете файлы, создайте новый файл с именем Makefile со следующим содержимым:

# which page numbers to fetch
numbers := $(shell seq 1 10)

# default target which depends on files 1.html .. 10.html
# (patsubst replaces % with %.html for each number)
all: $(patsubst %,%.html,$(numbers))

# the rule which tells how to generate a %.html dependency
# $@ is the target filename e.g. 1.html
%.html:
        curl -C - 'http://www...../?page='$(patsubst %.html,%,$@) -o $@.tmp
        mv $@.tmp $@

ПРИМЕЧАНИЕ Последние две строки должны начинаться с символа TAB ( вместо 8 пробелов) или make не примет файл.

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

make -k -j 5

Команда curl, которую я использовал, сохранит вывод в 1.html.tmp и только в случае успеха команды curl она будет переименована в 1.html (с помощью mv на следующей строке). Таким образом, если какая-то загрузка не удалась, вы можете просто повторно запустить ту же команду make, и она возобновит / попытается загрузить файлы, которые не удалось загрузить в первый раз. После того, как все файлы были успешно загружены, make сообщит, что больше ничего не нужно делать, поэтому не стоит вредить запускать его один раз, чтобы быть «безопасным».

(Переключатель -k указывает make продолжать загрузку остальных файлов, даже если одна загрузка не удалась.)

4
ответ дан Jonas Berlin 26 December 2011 в 08:31
поделиться

Я придумал решение, основанное на fmt и xargs. Идея состоит в том, чтобы указать несколько URL-адресов внутри фигурных скобок http://example.com/page{1,2,3}.html и запустить их параллельно с xargs. После этого начнется загрузка в 3 процесса:

seq 1 50 | fmt -w40 | tr ' ' ',' \
| awk -v url="http://example.com/" '{print url "page{" $1 "}.html"}' \
| xargs -P3 -n1 curl -o

, поэтому 4 загружаемых строки URL-адресов генерируются и отправляются на xargs

curl -o http://example.com/page{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}.html
curl -o http://example.com/page{17,18,19,20,21,22,23,24,25,26,27,28,29}.html
curl -o http://example.com/page{30,31,32,33,34,35,36,37,38,39,40,41,42}.html
curl -o http://example.com/page{43,44,45,46,47,48,49,50}.html
1
ответ дан Slava Ignatyev 26 December 2011 в 08:31
поделиться