我从一个网站获取了很多比较小的页面,想知道是否可以在Bash中以并行方式处理。目前我的代码看起来像这样,但是执行起来需要一段时间(我认为导致拖慢速度的是连接延迟)。
for i in {1..42}
do
wget "https://www.example.com/page$i.html"
done
我听说过使用xargs,但我对它一无所知,而且man手册非常令人困惑。你有什么建议吗?是否可以并行执行?还有其他方法可以解决这个问题吗?
我从一个网站获取了很多比较小的页面,想知道是否可以在Bash中以并行方式处理。目前我的代码看起来像这样,但是执行起来需要一段时间(我认为导致拖慢速度的是连接延迟)。
for i in {1..42}
do
wget "https://www.example.com/page$i.html"
done
我听说过使用xargs,但我对它一无所知,而且man手册非常令人困惑。你有什么建议吗?是否可以并行执行?还有其他方法可以解决这个问题吗?
使用xargs
可以达到与将wget
后台运行使用&
或-b
相同的效果,而且更好。
优点在于,xargs
会正确同步,无需额外工作。这意味着您可以安全地访问已下载的文件(假设没有发生错误)。所有下载将在xargs
退出时完成(或失败),并且您可以通过退出代码知道一切是否顺利。这比忙等待sleep
并手动测试完成要好得多。
假设URL_LIST
是包含所有URL的变量(可以使用OP示例中的循环构建,但也可以是手动生成的列表),则运行以下命令:
echo $URL_LIST | xargs -n 1 -P 8 wget -q
使用-n 1
参数将一个参数传递给wget
,并且最多同时执行8个并行的wget
进程(-P 8
)。xarg
会在最后一个已产生的进程完成后返回,这正是我们想要的结果,没有需要额外的技巧。
我选择的8个并行下载的“魔法数字”并不是一成不变的,但它可能是一个很好的折衷方案。有两个因素可以“最大化”一系列下载:
一是填满“电缆”,即利用可用带宽。假设“正常”情况下(服务器的带宽高于客户端),这已经是一个或最多两个下载的情况。增加更多连接只会导致数据包被丢弃和TCP拥塞控制 kicking in,并且 N 个下载每个呈现渐近于1/N的带宽,效果相同(减去丢失的数据包,减去窗口大小恢复)。在IP网络中,数据包被丢弃是正常发生的事情,这就是拥塞控制应该发挥作用的方式(即使是单个连接),通常影响几乎为零。然而,建立过多连接会放大此效应,因此可能会变得明显。不管怎样,这并不会使任何事情更快。
第二个因素是连接建立和请求处理。在这里,有几个额外的连接实际上非常有帮助。面临的问题是两个往返延迟(通常在同一地理区域内为20-40ms,在洲际之间为200-300ms)加上服务器实际需要处理请求并将其推送到套接字的奇怪的1-2毫秒。就本身而言,这并不是很长的时间,但乘以几百/千个请求,它很快就会累计起来。
拥有半打到一打请求在飞行中可以隐藏大部分或全部这种延迟(它仍然存在,但由于它重叠,所以不会总和!)。同时,只有少数并发连接不会产生负面影响,例如导致过度拥塞或强制服务器分叉新进程。
只是在后台运行任务不是一个可扩展的解决方案:如果你要获取10000个url,你可能只想并行获取几个(比如说100个)。GNU Parallel就是为此而生的。
seq 10000 | parallel -j100 wget https://www.example.com/page{}.html
请参阅该页面了解更多示例:http://www.gnu.org/software/parallel/man.html#example__download_10_images_for_each_of_the_past_30_days
-b
选项:wget -b "https://www.example.com/page$i.html"
如果您不需要日志文件,可以添加选项-o /dev/null
。
-o FILE 将日志消息记录到FILE文件中。
将&添加到命令中可以使其在后台运行
for i in {1..42}
do
wget "https://www.example.com/page$i.html" &
done
xargs
选项。这也是开发 GNU Parallel 的原因之一。 - Ole Tangecat ./urls | xargs -n 1 -P 8 wget [...]
,或者更好的方式是xargs -a ./urls -n 1 -P 8 wget [...]
,而不是将文件读入变量中。 - Hitechcomputergeek