[Linux] 쉘 스크립트에서 멀티프로세스(혹은 스레드) 기능 사용하기

백그라운드로 명령어를 실행해서 병렬적으로 실행되는 멀티 프로세스 환경을 만들어보자.


환경

  • Linux 기반 시스템
  • Bash shell(/bin/bash)


멀티프로세스? 병렬처리? 멀티스레드? 백그라운드 프로세스?

  • 여기서 진행할 방식은 & 연산자를 이용해 명령어나 쉘스크립트의 내용을 백그라운드로 실행시키는 방식을 사용할 예정입니다.
  • 여기저기 찾아본 결과 & 연산자를 이용하면 해당 명령어나 스크립트는 현재 실행되는 프로세스의 자식 프로세스를 생성하여 새로운 서브쉘에서 실행된다고 합니다.
  • 정확하게 명칭을 멀티프로세스나 멀티스레드라고 부르기 애매하나… 영문 자료들에서 & 연산자를 이용해 자식 프로세스를 만든다고 하여 멀티프로세스라고 이름 지었습니다. 혹시 다른 내용이나 더 정확한 내용을 알고 계시면 자료 첨부와 함께 댓글 달아주시면 감사하겠습니다 :)


리눅스 &(Ampersand) 연산자

& 연산자란?

  • 리눅스 환경에서 명령어를 실행할 때 현재 사용하고 있는 쉘이 아닌 새로운 서브쉘을 생성해서 백그라운드에서 실행할 때 사용하는 명령어입니다.
  • &를 사용해서 명령어나 스크립트를 실행하면 백그라운드로 해당 명령어나 스크립트가 실행되며 쉘에서 다른 작업을 계속 할 수 있습니다.
  • 다음 아래 예제들처럼 원하는 명령어를 다 입력한 후에 &를 붙여주면 됩니다.


& 연산자 예제

  • (예제) sleep을 백그라운드에서 실행하기
$ sleep 10 &
[1] 79287
$ # Type enter to make below result
[1]+  Done                    sleep 10
  • (예제) shell script를 백그라운드에서 실행하기
  • 다음 아래처럼 명령어 > 파일명 & 방식을 이용해 stdout을 로그파일로 남길수도 있습니다.
$ tee test_shell.sh << EOF
> #!/bin/bash
>
> echo 1
> sleep 1
> echo 2
> sleep 1
> echo 3
> EOF
echo 1
sleep 1
echo 2
sleep 1
echo 3
$ ./test_shell.sh > tmp_test_shell.log & # You can redirect stdout to specific file.


(예제) 쉘스크립트 함수를 백그라운드에서 병렬로 사용하기

설명

  • 함수를 만들고 해당 함수에 인자를 전달해서 백그라운드로 돌리는 예제를 작성해보겠습니다.
  • 아래 예제는 배열에 있는 원소들을 인자로 전달하여 랜덤한 값에 따라 sleep을 하는 스크립트입니다. &를 사용하지 않는다면 각각 배열의 원소에 대하여 랜덤한 시간만큼 sleep이 끝날 때까지 순차적으로 기다리겠지만 &를 사용했기 때문에 각각의 작업은 백그라운드에서 따로 진행됩니다.
  • 각각 자식 프로세스들이 잘 생성되고 실행되었는지를 확인하기 위해 배열 원소의 이름으로 로그 파일을 만들었습니다.


코드

test_multi_process.sh

#!/bin/bash

function back_ground_process () {
	# Random number between 10 and 15
	sleep_time=$(($RANDOM*12345%6 + 10))

	echo "${1} will sleep for ${sleep_time} seconds"

	sleep ${sleep_time}

	echo "${1} sleep done!"
}

# array in shell script
arr=("a_worker" "b_worker" "c_worker")

# @ means all elements in array
for i in ${arr[@]}; do
    # run back_ground_process function in background
    # pass element of array as argument
    # make log file
    back_ground_process $i > ~/log_${i}.txt &
done
  • wait라는 명령어를 사용하면 현재 실행된 스크립트에서 생성된 모든 자식 프로세스 및 백그라운드 작업을 기다릴수 있습니다.

test_multi_process.sh(continue)

...
# @ means all elements in array
for i in ${arr[@]}; do
    # run back_ground_process function in background
    # pass element of array as argument
    # make log file
    back_ground_process $i > ~/log_${i}.txt &
done

# wait until all child processes are done
wait

echo "All background processes are done!"


결과

  • 실행하고 바로 로그 파일들을 확인합니다.
  • 쉘 스크립트는 백그라운드로 작업을 각각 돌리고 바로 종료되는걸 볼 수 있습니다.
$ ./test_multi_process.sh
$ cat log_a_worker.txt && cat log_b_worker.txt && cat log_c_worker.txt
a_worker will sleep for 13 seconds
b_worker will sleep for 13 seconds
c_worker will sleep for 10 seconds
  • 15초 정도가 지난후에 로그파일들을 보면 각각의 프로세스가 끝났음을 알 수 있습니다.
$ cat log_a_worker.txt && cat log_b_worker.txt && cat log_c_worker.txt
a_worker will sleep for 13 seconds
a_worker sleep done!
b_worker will sleep for 13 seconds
b_worker sleep done!
c_worker will sleep for 10 seconds
c_worker sleep done!


응용

  • 위와 같이 &를 사용해서 사용하고 싶은 데몬이나 프로세스들을 백그라운드로 실행할 수 있습니다.
  • 예를 들어서 여러개의 컴퓨터에 동시에 접속해서 어떤 파일을 설치하는 명령어들을 백그라운드로 병렬로 실행해서 시간을 단축시킬 수 있으며 현재 쉘에서 특정 프로그램을 실행 시키고 계속 현재 쉘을 사용하고 싶을 때 유용합니다.
  • 추가적으로 쉘 스크립트에서 백그라운드로 멀티 프로세스를 진행시키고 싶을 때 사용이 가능합니다.


참고자료