<分区>
我从一个网站上获得了一堆相对较小的页面,我想知道我是否可以在 Bash 中以某种方式并行执行这些操作。目前我的代码看起来像这样,但需要一段时间才能执行(我认为让我变慢的是连接延迟)。
for i in {1..42}
do
wget "https://www.example.com/page$i.html"
done
我听说过使用 xargs,但我对此一无所知,而且手册页非常困惑。有任何想法吗?甚至可以并行执行此操作吗?还有其他方法可以解决这个问题吗?
<分区>
我从一个网站上获得了一堆相对较小的页面,我想知道我是否可以在 Bash 中以某种方式并行执行这些操作。目前我的代码看起来像这样,但需要一段时间才能执行(我认为让我变慢的是连接延迟)。
for i in {1..42}
do
wget "https://www.example.com/page$i.html"
done
我听说过使用 xargs,但我对此一无所知,而且手册页非常困惑。有任何想法吗?甚至可以并行执行此操作吗?还有其他方法可以解决这个问题吗?
最佳答案
比使用 &
或 -b
将 wget
插入后台更可取,您可以使用 xargs
来效果一样,而且更好。
优点是 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 拥塞控制开始,N 以渐进的 1/N 带宽下载每个,达到相同的净效果(减去丢弃的数据包,减去窗口大小恢复)。丢包在 IP 网络中是很正常的事情,这就是拥塞控制的工作原理(即使是单个连接),通常影响几乎为零。然而,拥有不合理的大量连接会放大这种影响,因此它会变得很明显。无论如何,它不会使任何事情变得更快。
第二个因素是连接建立和请求处理。在这里,在飞行中建立一些额外的联系真的很有帮助。一个人面临的问题是两次往返的延迟(在同一地理区域内通常为 20-40 毫秒,洲际之间为 200-300 毫秒)加上服务器实际需要处理请求和推送回复的奇数 1-2 毫秒到 socket 。这不是很多时间本身,但乘以几百/千个请求,它很快就会加起来。
从六个到十几个请求中的任何东西都隐藏了大部分或全部这种延迟(它仍然存在,但由于它重叠,所以它没有总结!)。同时,只有少数并发连接不会产生不利影响,例如导致过度拥塞或迫使服务器 fork 新进程。
关于bash - Bash 中的并行 wget,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7577615/