同时运行多个curl命令

83

我有以下shell脚本。问题是我想要并行/同时运行交易,而不必等待一个请求完成后才去下一个请求。例如,如果我发出20个请求,我希望它们能够同时执行。

for ((request=1;request<=20;request++))
do
    for ((x=1;x<=20;x++))
    do
        time curl -X POST --header "http://localhost:5000/example"
    done
done

有任何指南吗?


2
curl -X POST ... &? - Ruslan Osmanov
1
如果您有兴趣对特定的URL进行负载测试,并且不一定坚持使用curl,也许hey会引起您的兴趣。 - philonous
8个回答

95
您可以使用xargs命令的-P选项来并行运行任何命令:
seq 1 200 | xargs -n1 -P10  curl "http://localhost:5000/example"

这将以最多10个任务并行的方式运行curl命令200次。


6
对我来说,它也与0.0.0.1、0.0.0.2等相连。 - Madhur Ahuja
2
这对我有效,但由于某种原因,它在完成命令后不会退出,并保持所有连接开放(使用 netstat -an | wc -l 查看打开的连接)。导致这种情况的原因是什么?有没有办法让它在结束时退出? - thinktt
18
是的,它在curl命令的末尾添加了数字。简单的解决方法是这样的: seq 1 200 | xargs -Iname -P10 curl "http://localhost:5000/example"使用_I_参数来指定参数的占位符,然后在命令调用中省略参数。 - dark knight

72
使用xargs -P选项,您可以并行运行任何命令:
xargs -I % -P 8 curl -X POST --header "http://localhost:5000/example" \
< <(printf '%s\n' {1..400})

这将使用curl命令在一次最多并行8个作业的情况下运行400次。

1
-P 会并行运行指定数量的进程。printf '%s\n' {1..400} 将打印从1到400的数字,而 curl 则会最多并行运行8个任务,总共运行400次。 - anubhava
是否可以将每个输出打印在新行中? - anoopelias
3
请参考此答案:https://stackoverflow.com/a/61249019/548225,您可以在`xargs`中运行bash脚本,并在其中执行任何操作。 - anubhava
该命令无法正常工作。 请尝试将其复制到命令行并执行。 它将返回: bash: 0: ambiguous redirect - Max
当然,在bash 4或5版本上没有任何错误。在旧的bash版本中使用:printf '%s\n' {1..400} | xargs -I % -P 8 curl -I -X POST 'http://localhost:5000/example' - anubhava
2
我曾认为重复使用同一TCP连接会更快,因此curl --parallel应该比xargs -P n更快。但是我发现,对于每个请求,xargs在使用connection: close时速度更快!请问为什么?curl是否看到并重用了并行作业的相同连接? - Mamdouh Saeed

30

2020年更新:

Curl现在可以并行获取多个网站:

curl --parallel --parallel-immediate --parallel-max 3 --config websites.txt

网站.txt文件:

url = "website1.com"
url = "website2.com"
url = "website3.com"

3
在这种情况下,POST数据是如何工作的? - Josh
2
@Josh 你可以像这样发送多个POST请求: curl -i --parallel --parallel-immediate --parallel-max 3 -X POST -H 'Content-Type: application/json' -d '{"x":100}' --config websites.txt - László Kenéz
并行运行数千个请求怎么样?Curl 能胜任吗? - Morty
如何通过相同的TCP连接和相同的URL发送多个数据?我知道--next,但是我觉得重复相同的长URL、不同的-d值和-H值让我感到很愚蠢,这导致了错误参数列表太长 - Mamdouh Saeed
如果你想让curl在跟随重定向后获取远程文件名,你可以添加-L--remote-name-all选项。 - Tom Nguyen
对我来说不起作用。仍然按顺序运行并等待POST请求完成。 - undefined

12

这是对@saeed回答的补充。

我遇到了一个问题,它向以下主机发送了不必要的请求。

0.0.0.1, 0.0.0.2 .... 0.0.0.N

原因是命令xargs将参数传递给curl命令。为了防止传递参数,我们可以使用-I标志来指定要替换参数的字符。

因此,我们将如下使用:

 ... xargs -I '$' command ...

现在,xargs 将替换任何发现 $ 字面量的参数。如果未找到,则不传递该参数。因此,使用它的最终命令将是:

seq 1 200 | xargs -I $ -n1 -P10  curl "http://localhost:5000/example"

注意:如果你在命令中使用了 $ 符号,请尝试将其替换为其他未使用的字符。


7

补充@saeed的答案,我创建了一个通用函数,利用函数参数在并行执行中的M个任务中总共触发N次命令。

function conc(){
    cmd=("${@:3}")
    seq 1 "$1" | xargs -n1 -P"$2" "${cmd[@]}"
}

$ conc N M cmd
$ conc 10 2 curl --location --request GET 'http://google.com/'

这将会最多并行执行两个curl命令的10个命令。
将此函数添加到bash_profile.rc中可以使其更容易。 Gist

1
谢谢,非常方便。需要注意的是,xargs将从seq读取的索引传递给命令。例如,conc 2 2 echo test将打印test 1\ntest 2。为了避免这种情况,使用-I'$XARGI'而不是-n1可以解决问题(如果需要索引,则可以在命令中使用$XARGI,否则可以省略)。 - Dario Seidl

2
在结尾处加上“wait”,并将它们后台运行。
for ((request=1;request<=20;request++))
do
    for ((x=1;x<=20;x++))
    do
        time curl -X POST --header "http://localhost:5000/example" &
    done
done

wait

他们都会输出到同一个stdout,但你可以将时间的结果(以及stdout和stderr)重定向到一个命名文件中:
time curl -X POST --header "http://localhost:5000/example" > output.${x}.${request}.out 2>1 &

我尝试过这个,但它给了我其他问题。虽然这很有帮助,但让我们也将时间重定向到文件中。 - user5836023
“输出到文件”问题比较棘手,可能需要通过GNU并行工具发送到同步缓冲区、命名管道或flock。 - Gaétan RYCKEBOER

2

我想分享一下如何利用平行的xargs和curl。这与IT技术有关。

使用xargs的好处是可以指定使用多少线程来并行处理curl,而不是使用“&”符号来同时调度所有的curl,例如10000个。

希望对大家有所帮助。

#!/bin/sh

url=/any-url
currentDate=$(date +%Y-%m-%d)
payload='{"field1":"value1", "field2":{},"timestamp":"'$currentDate'"}'
threadCount=10

cat $1 | \
xargs -P $threadCount -I {} curl -sw 'url= %{url_effective}, http_status_code = %{http_code},time_total = %{time_total} seconds \n' -H "Content-Type: application/json" -H "Accept: application/json" -X POST $url --max-time 60 -d $payload

.csv文件每行有一个值,这些值将被插入到JSON有效载荷中。


0
基于@isopropylcyanide提供的解决方案和@Dario Seidl的评论,我认为这是最好的回答,因为它可以同时处理curl和httpie。
# conc N M cmd - fire (N) commands at a max parallelism of (M) each
function conc(){
    cmd=("${@:3}")
    seq 1 "$1" | xargs -I'$XARGI' -P"$2" "${cmd[@]}"
}

例如:

conc 10 3 curl -L -X POST https://httpbin.org/post -H 'Authorization: Basic dXNlcjpwYXNz' -H 'Content-Type: application/json' -d '{"url":"http://google.com/","foo":"bar"}'

conc 10 3 http --ignore-stdin -F -a user:pass httpbin.org/post url=http://google.com/ foo=bar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接