백그라운드에서 다른 프로세스를 실행하여 실행 중인 최대 프로세스 수(이 경우 300개)를 제어하는 스크립트가 있습니다.
처음에는 스크립트를 대략적으로 실행합니다. 1~2ms이지만 몇 시간 동안 실행한 후에는 결국 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
원본 코드.
시작할 때 cli.php
시작하는 데 걸리는 시간을 측정하려고 하므로 300개의 복사본만 시작하면 됩니다. 이는 약 1200개의 프로세스여야 합니다.
그런 다음 변수를 crd
300에서 9999999까지 반복합니다.
쉘이
threads
어레이에 여유 슬롯이 있다고 판단하면cli.php
4개의 프로세스를 사용하여 새 슬롯을 시작합니다.그렇지 않으면 약 300개의 프로세스를 반복하여
커널이/proc
가상 파일 시스템을 채우고
디렉터리가 존재하는지 테스트하게 됩니다. 누락된 디렉토리가 있으면 해당 항목이 어레이
에서 제거됩니다.threads
이름이 사용되지 않은 배열이 있습니다 crds
.
초기 300개 이후 cli.php
프로세스 테이블에 사용 가능한 슬롯이 있으면 crd 변수의 각 루프는 1개의 새 복사본을 생성하지만 테이블이 가득 차면 최대 300개의 복사본을 삭제할 수 있으므로 실행이 끝나면 단지 300개에서 약 9,967,000개의 cli.php
프로세스가 시작된 것으로 알려져 있으며 , 프로세스 수는 컴퓨터 속도, cli.php
실행 시간, 컴퓨터 부하에 따라 달라집니다. 최적화할 수 있는 크기는 6개입니다!
경험상 최신 시스템에서는 하나의 프로세스를 실행하는 데 하나의 코어에서 1밀리초가 걸리므로 초기 실행 속도에서는 문제가 없습니다. 새로운 프로세스를 시작하기 위해 사용 가능한 코어가 부족해지면 시작 속도가 크게 바뀔 것으로 예상됩니다.
개선하다
속도를 높이는 한 가지 방법은 ! kill -0 $pid
아무것도 죽이지 [ ! -d "/proc/${pid}" ]
않지만 kill -0
프로세스가 존재하지 않으면 오류를 반환하는 것을 사용하는 것입니다. kill
은 쉘 내장(있는 그대로 [
)이지만 커널에서 수행할 작업이 적습니다. 이는 대부분의 시간 동안 어레이에 사용 가능한 슬롯이 없는 경우 가장 효율적입니다 threads
.
expr
두 번째 개선 사항은 외부 프로그램 호출 대신 내장된 연산을 사용하여 $(( ... ))
시작 시간을 줄이는 것입니다 cli.php
. 이는 대부분의 시간 동안 배열에 여유 슬롯이 있는 경우에 가장 효율적입니다 labels
.
더 많은 분석을 수행하려면 cli.php
실행하는 데 걸리는 대략적인 시간과 실행 횟수를 알아야 합니다.
BUGS
Bash 매뉴얼 섹션에서 언급했듯이 Bash It's too big and too slow.
의 배열 구현에는 확실히 개선의 여지가 있습니다.
대체 구현
만들다
의견에 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
해결책을 찾으 려면
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