うまくいかない

うまくいかない

次のスクリプトを実行しています。

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の柔軟性をお楽しみください ;)

関連情報