次のスクリプトを実行しています。
LOGDIR=~/curl_result_$(date |tr ' :' '_')
mkdir $LOGDIR
for THREADNO in $(seq 20)
do
for REQNO in $(seq 20)
do
time curl --verbose -sS http://dummy.restapiexample.com/api/v1/create --trace-ascii ${LOGDIR}/trace_${THREADNO}_${REQNO} -d @- <<EOF >> ${LOGDIR}/response_${THREADNO} 2>&1
{"name":"emp_${THREADNO}_${REQNO}_$(date |tr ' :' '_')","salary":"$(echo $RANDOM%100000|bc)","age":"$(echo $RANDOM%100000|bc)"}
EOF
echo -e "\n-------------------------------" >> ${LOGDIR}/response_${THREADNO}
done 2>&1 | grep real > $LOGDIR/timing_${THREADNO} &
done
しばらくしてbashプロセスがないことを確認すると、20(1または21ではありません)が表示されます。
ps|grep bash|wc -l
問題は、内部ループを囲むために角括弧「()」を使用しないため、新しいシェルプロセスを作成してはいけません。 CPU使用率が100%に近いときに新しいシェルを作成しないようにします。これが重要かどうかはわかりませんが、Cygwinを使用しています。
答え1
ループをパイプに入れたので、サブシェルgrep
で実行する必要があります。これが言及されましたバッシュマニュアルから:
パイプラインの各コマンドは、個別のプロセスである独自のサブシェルで実行されます(参照:コマンド実行環境)
これは次の方法で回避できます。lastpipe
住宅オプション~のため決定的なパイプラインにはコマンドがありますが、他のコマンドにはありません。とにかく、パイプライン全体をバックグラウンドに配置しました。返品サブシェルを作成します。
この問題を解決する方法はありません。デフォルトでは、実行する操作には別のシェルプロセスが必要です。バックグラウンドプロセスを作成するには、パイプを無視してもプロセスを作成する必要があります。
問題がCPU使用率であれば、すべてを同時に実行したために発生しました。削除すると、すべてのコマンド&
がgrep
同時に実行されるのではなく、順次実行されます。サブシェルはまだ生成されますが(パイプ用)この場合、それ自体は主な問題ではありません。同時に実行する必要がある場合は、CPU使用量の増加を選択することをお勧めします。
答え2
うまくいかない
Bash はスレッド並列性をサポートせず、マルチプロセス並列性をサポートします。
Bashは子プロセスを作成しないとバックグラウンドでforループ(またはパイプ)を実行できません。驚くべきことに、bashプロセスは21ではなく20です。
私はCygwinについて何も知りません。
代替
Pythonに精通している場合は、Plumbumライブラリを使用することをお勧めします。 Pythonはスレッドをサポートしているので、すべてが簡単になります。
書き換えてテストしたコードは次のとおりです。
from datetime import datetime
import json
import random
from plumbum import cmd as c
from threading import Thread
def now():
return datetime.now().strftime("%Y-%m-%d %H_%M_%S")
logdir = f"~/curl_result_{now()}"
def curl(threadno, reqno):
args1 = "--verbose -sS http://dummy.restapiexample.com/api/v1/create --trace-ascii".split()
args2 = [f"{logdir}_{threadno}_{reqno}", "-d", "@-"]
content = json.dumps({
"name": f"{logdir}/trace_{threadno}_{reqno}_{now()}",
"salary": random.randrange(100_000),
"age": random.randrange(100_000) ,
})
call = c.echo[content] | c.curl[(*args1, *args2)] >> f"{logdir}/response_{threadno}"
print(call)
# call()
def curl_batch(threadno):
for reqno in range(20):
curl(threadno, reqno)
# Start 20 threads
threadList = []
for threadno in range(20):
t = Thread(target=curl_batch, args=(threadno,))
t.start()
threadList.append(t)
# Wait for every thread
for thread in threadList:
thread.join()
Pythonの柔軟性をお楽しみください ;)