재귀 쉘 최대 기능의 속도를 높이기 위해 병렬성을 사용하시겠습니까?

재귀 쉘 최대 기능의 속도를 높이기 위해 병렬성을 사용하시겠습니까?

배열에서 가장 높은 값(350 int 값)을 찾으려면 max 함수가 필요했고 재귀의 친구로서 재귀 접근 방식을 시도했습니다.

max () {
    len=$#
    a=$1
    b=$2
    case $len in
        0)
            echo NaN
            ;;
        1)
            echo $1
            ;;
        2)
            (( a > b )) && echo $a || echo $b
            ;;
        *)
            shift; shift
            max $(max $a $b) $(max $@)
            ;;
    esac
}

놀라울 정도로 느립니다. 350개의 값은 2.6초가 소요됩니다.

예, 정식 유닉스 방식은 다음과 같습니다.

time (echo ${yvals[@]} | tr " " "\n" | sort -n | tail -n 1 )

0,005초와 while 루프가 소요됩니다.

max () {
    anz=$#
    max=$1
    while ((anz > 0))
    do
        b=$2
        (( b > max )) && max=$b
        shift
        anz=$#
    done
    echo $max
}

0,010초와 크게 다르지 않습니다. 두 배 느린 속도이지만 값이 너무 낮으면 오차 범위가 측정된 값보다 높을 수 있습니다. 값 개수가 너무 높지 않은 한 가장 빠른 성능에는 별로 관심이 없습니다. 하지만 gnu-parallel이 개선을 가져올 수 있을지 궁금해서 오랫동안 병렬성에 대해 더 많이 배울 수 있는 기회를 기다려왔지만 실제 사례를 통해 배우는 것을 선호하고 사례가 거의 없습니다. , 이는 병렬화의 이점을 누릴 수 있습니다.

그래서 나의 순진한 접근 방식은 재귀 버전을 시도하는 것이었습니다.

time parallel max ::: ${yvals[@]} 

그리고 -j+0과 같은 몇 가지 병렬 실험 옵션을 추가했습니다. 이 옵션은 350개의 값을 생성하며 각 값은 다른 값과 비교되지 않으므로 그 자체가 최대값입니다. :)

맨페이지를 참조한 것 외에도 Ole Tange의 YT 동영상 4개 중 2개도 시청했습니다.GNU 병렬, 약간의 수정을 거쳐 채택할 수 있을 만큼 내 사용 사례에 가까운 예제를 찾았지만 아무 것도 찾지 못했습니다.

그래서 SE에게 물어볼 생각이 있었지만 다른 일로 주의가 산만해지고 6개의 셸 창 기록이 엉망이 되어 질문을 쓰기 시작했고 명령을 기록하고 싶었습니다. 시도했지만 지금은 다음과 같이 썼습니다.

time parallel -X max ::: ${yvals[@]} 
6933
1689
23676
31553

놀랍게도 실제로 작동합니다. 예, 코어가 4개이므로 4개의 결과가 있으며 어느 것이 가장 큰지 쉽게 파악할 수 있습니다. 이러한 최대값 중 최대값을 취하는 max 함수를 작성할 수 있습니다.

time max $(parallel -X max ::: ${yvals[@]}) 
31553

real    0m0,501s (Only a 5th of the time, used without parallel).

따라서 0.5초는 셸에서 대화식으로 작업하는 데 허용되는 범위이지만, 물론 이 경험을 달성하는 것은 단지 행운과 적절한 레코드 수일 뿐입니다. 쉘이 재귀 성능이 좋지 않은 것으로 알려져 있습니까? 이것은 내 주요 문제가 아닙니다.

주요 질문은 결과에 대해 함수를 다시 실행하는 정식 병렬 방법이 있는지 여부입니다. 이는 함수형 프로그래밍의 문제를 해결하는 일반적인 방법입니다.. 지도/감소는 원칙적으로 동일하다고 생각합니다.

대부분의 경우 내가 다루는 데이터가 작기 때문에 병렬 처리에 들어가고 나가는 방법을 배울 기회와 고통이 부족합니다.

답변1

maxBash의 처음 500개 값에 대해 함수는 O(n^2) 시간에 실행됩니다. 이는 max잔존 가치로 통화를 했기 때문일 가능성이 높습니다 . 따라서 이 값을 복사해야 합니다.

mmax() {
    max $(seq $1)
}

seq 10000 | env_parallel --joblog bash.log mmax
(echo '#Bash';echo '#JobRuntime in seconds';field 10,4 < bash.log |sort -n) |
  head -n 1000 | plotpipe

여기에 이미지 설명을 입력하세요.

처음 1000개 값의 경우 상황이 약간 혼란스럽습니다.

여기에 이미지 설명을 입력하세요.

ksh처음 500개 값 에 대해서는 명확하지 않습니다.

여기에 이미지 설명을 입력하세요.

그러나 1000개의 값에 대해서는 O(n^2)처럼 보입니다.

여기에 이미지 설명을 입력하세요.

ksh12:37에 충돌 발생:

여기에 이미지 설명을 입력하세요.

( plotpipe그리고 field다음에서:https://gitlab.com/ole.tange/tangetools).

관련 정보