실행 중인 최대 프로세스 수(이 경우 300개)를 제어하려고 시도하는 다른 프로세스를 백그라운드로 실행하는 스크립트를 생각해 냈습니다.
처음에는 약에서 스크립트를 실행합니다. 1~2밀리초이지만 몇 시간 실행한 후에는 결국 선형 경사로 200ms~350ms 실행 속도로 느려집니다. PID#을 유지하기 위해 배열을 사용하고 테이블 크기를 줄이기 위해 키를 설정 해제하고 있지만 그게 범인이라는 느낌이 듭니다.
#!/bin/bash
threads=()
threadcounter=0
crd=0;
while true;
do
threadcounter=${#threads[@]}
crdcounter=${#crds[@]}
if [ "$threadcounter" -lt 300 ]
then
s1=$(($(date +%s%N)/1000000))
pidf=$(/opt/remi/php/root/usr/bin/php cli.php initformula $crd >> /tmp/logger) &
pidfid=$!
s2=$(($(date +%s%N)/1000000))
echo "Init " $crd $(expr $s2 - $s1 ) "ms"
threads[$pidfid]+=$pidfid
else
for pid in "${!threads[@]}"; do
if [ ! -d "/proc/${pid}" ]
then
unset threads[$pid]
fi
done;
fi;
if [ "$crd" -gt 9999999 ]
then
echo "completed all";
exit;
fi;
crd=$(expr $crd + 1)
done;
답변1
원본 코드.
시작하면 300개의 복사본만 시작하면 됩니다 cli.php
. 실행하는 데 걸리는 시간을 측정하려고 하므로 약 1200개의 프로세스가 필요합니다.
그런 다음 변수를 crd
300에서 9999999까지 반복합니다.
쉘이 어레이에 여유 슬롯이 있다고 생각하면 4개의 프로세스를 사용하여
threads
새 슬롯을 시작합니다 .cli.php
그렇지 않으면 커널이 가상 파일 시스템을 채우도록/proc
하고 디렉토리가 존재하는지 테스트하는 약 300개 이상의 프로세스를 반복합니다
. 누락된 디렉토리가 있으면 항목이 어레이
에서 삭제 됩니다threads
.
라는 사용되지 않은 배열이 있습니다 crds
.
처음 300개 이후 crd 변수의 각 루프는 프로세스 테이블에 사용 가능한 슬롯이 있는 경우 1개의 새 복사본을 생성 cli.php
하지만 테이블이 가득 차면 최대 300개까지 제거할 수 있기 때문에 실행이 끝날 때 우리는 300개에서 약 9,967,000개 사이의 cli.php
프로세스가 시작되었으며, 숫자는 시스템 속도, cli.php
실행 시간 및 시스템 로드에 따라 결정됩니다. 6배의 크기는 최적화해야 할 것이 많습니다!
경험상 최신 시스템에서는 프로세스 1개를 시작하는 데 코어 하나에서 1ms가 걸리므로 초기 실행 속도에서는 나쁘지 않습니다. 새로운 프로세스를 시작하기 위한 여유 코어가 부족해지면 실행 속도가 크게 달라질 것으로 예상됩니다.
개량
속도를 높이는 한 가지 방법은 - 아무것도 죽이지 않지만 프로세스가 존재하지 않으면 오류 반환을 제공하는 ! kill -0 $pid
대신 사용하는 것입니다. 는 쉘에 내장되어 있지만(있는 그대로 ) 커널이 수행해야 하는 작업의 양은 더 적습니다. 이는 대부분의 경우 어레이에 사용 가능한 슬롯이 없는 경우 가장 효과적입니다 .[ ! -d "/proc/${pid}" ]
kill -0
kill
[
threads
두 번째 개선 사항은 외부 프로그램에 대한 호출을 내장된 산술 연산을 expr
사용하여 대체하여 . 이는 대부분의 시간 동안 어레이에 여유 슬롯이 있는 경우 가장 효과적입니다 .$(( ... ))
cli.php
labels
cli.php
더 많은 분석을 수행하려면 실행하는 데 걸리는 대략적인 시간과 실행 횟수를 알아야 합니다 .
BUGS
Bash 매뉴얼의 섹션에서 알 수 있듯이 It's too big and too slow.
Bash의 배열 구현을 개선할 여지가 있다는 것은 확실히 가능합니다.
대체 구현
만들다
의견에서는 xargs
또는 를 사용하는 것이 좋습니다 parallel
. 나는 종종 make
. 가장 먼저 cli.php
원하는 사본 수를 결정합니다 . 그런 다음 다음 Makefile
과 같은 간단한
%:
\t/opt/remi/php/root/usr/bin/php cli.php initformula $@
여기서 \t는 탭 문자입니다. (이 간단한 버전에서는 0~9999999 범위의 숫자 이름을 가진 파일이 없다고 가정합니다.) 그런 다음 make를 호출하십시오.
make -O -j 300 $(seq 0 9999999) > /tmp/logger
전체 10,000,000개의 cli.php 호출을 원하는 경우. cli.php가 오류를 반환하는 경우 처리를 중단하기 위해 과도한 조치를 취할 필요가 없다는 점을 포함 make
하고 싶은 이유 .xargs
xargs
xargs
해결책을 찾으 려면
seq 0 9999999 | xargs -n 1 -P 300 /opt/remi/php/root/usr/bin/php cli.php initformula > /tmp/logger
더 간단합니다.
세게 때리다
wait -nf
그러나 PID 추적을 전혀 걱정하지 않고 사용하는 Bash 솔루션은 OP의 취향에 더 적합할 수 있습니다. 초기 300개의 프로세스를 시작한 다음 그 중 하나가 완료되는 것을 감지하면 다른 프로세스가 시작됩니다. 10,000,000번째 작업이 시작되면 모든 작업이 완료될 때까지 최종 대기를 수행합니다. 정확히 동일한 알고리즘은 아니지만 매우 유사합니다.
#!/bin/bash
for(crd=0;crd<300;crd++); do
/opt/remi/php/root/usr/bin/php cli.php initformula $crd &
done > /tmp/logger
for(;crd<=9999999;crd++); do
wait -fn
/opt/remi/php/root/usr/bin/php cli.php initformula $crd &
done >> /tmp/logger
wait