xargs -P와 백그라운드 작업을 활용한 병렬 처리
xargs 병렬 모드와 관리되는 백그라운드 작업 풀을 사용하여 독립적인 작업을 동시에 실행합니다.
xargs -P와 백그라운드 작업을 활용한 병렬 처리은(는) CoddyKit의 무료 Linux Command Line & Bash Scripting Mastery 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Linux Command Line & Bash Scripting Mastery 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Linux Command Line & Bash Scripting Mastery 강의에는 총 4개의 강의가 포함되어 있습니다.
순차 실행이 느린 이유
셸 스크립트에서 명령을 하나씩 실행하면 CPU 코어가 유휴 상태로 남습니다. 이미지 500개의 크기를 조정한다고 생각해 보십시오. 각 convert 호출은 코어 하나를 사용하는 동안 나머지 7개 코어는 유휴 상태가 됩니다.
병렬 처리는 여러 작업을 동시에 배분하여 이 문제를 해결합니다. Bash에서는 다음 두 가지 주요 도구를 사용하면 쉽게 병렬 처리를 구현할 수 있습니다.
- xargs -P — 입력 목록을 N개의 병렬 작업 프로세스에 분산합니다.
- 백그라운드 작업(&) + wait — 프로세스를 직접 생성하고 완료를 수집합니다.
이 강의에서는 두 접근 방식을 모두 다루므로, 각 상황에 맞는 도구를 선택할 수 있습니다.
xargs 기초 복습
병렬 처리를 추가하기 전에 xargs의 작동 방식을 되짚어 보겠습니다. xargs는 표준 입력에서 항목을 읽어 명령의 인수로 전달합니다.
-I {} 플래그를 사용하면 입력 항목을 명령 문자열의 끝뿐 아니라 원하는 위치에 배치할 수 있습니다.
아래 예제에서는 tr을 사용해 모든 .txt 파일을 대문자로 변환합니다. 각 파일은 한 번에 하나씩 처리됩니다(순차 실행 기준).
#!/usr/bin/env bash
# Create sample files
mkdir -p /tmp/xargs_demo
for i in 1 2 3; do
echo "hello world $i" > /tmp/xargs_demo/file$i.txt
done
# Process files one at a time (sequential)
find /tmp/xargs_demo -name '*.txt' | xargs -I {} sh -c 'tr a-z A-Z < "$1"' _ {}
# Cleanup
rm -rf /tmp/xargs_demoxargs -P 소개
-P N 플래그를 xargs에 추가하면 최대 N개의 프로세스를 병렬로 실행할 수 있습니다. xargs가 작업 프로세스 풀을 자동으로 관리하므로, 슬롯 하나가 비면 다음 항목이 즉시 시작됩니다.
-P 0— 입력 수만큼 프로세스를 생성합니다(큰 목록에서는 주의해서 사용하십시오).-P 4— 언제든 최대 4개의 작업 프로세스를 실행합니다.-n 1— 실행되는 각 프로세스에 입력 항목을 정확히 하나씩 전달합니다(자주 함께 사용하는 플래그).
-n 1 -P 4를 함께 사용하면 가장 일반적인 패턴이 됩니다. 작업 프로세스 하나당 항목 하나를 할당하고, 동시에 4개의 작업 프로세스를 실행합니다.
#!/usr/bin/env bash
# Simulate 8 tasks, each taking ~1 second
# Sequential would take ~8s; parallel with -P 4 takes ~2s
process_item() {
local item="$1"
sleep 1
echo "Done: $item"
}
export -f process_item
time printf '%s\n' task{1..8} | xargs -n 1 -P 4 bash -c 'process_item "$@"' _파일 병렬 처리
실용적인 사용 사례로 많은 로그 파일을 동시에 압축하는 작업을 살펴보겠습니다. -P가 없으면 각 gzip 호출이 다음 호출을 막습니다. -P 8을 사용하면 최대 8개의 압축 작업이 동시에 실행되어 모든 CPU 코어를 활용합니다.
-n 1을 사용하면 각 병렬 작업 프로세스가 파일 이름을 정확히 하나씩 받는다는 점에 유의하십시오. 파일 이름에 공백이 포함될 수 있을 때 매우 중요합니다(안전하게 처리하려면 -d '\n' 또는 -print0 / -0과 함께 사용하십시오).
#!/usr/bin/env bash
# Create dummy log files
mkdir -p /tmp/logs_demo
for i in $(seq 1 12); do
dd if=/dev/urandom bs=1K count=64 2>/dev/null > /tmp/logs_demo/app_$i.log
done
echo "Files before: $(ls /tmp/logs_demo | wc -l)"
# Compress all .log files in parallel (up to 8 workers)
find /tmp/logs_demo -name '*.log' -print0 \
| xargs -0 -n 1 -P 8 gzip --fast
echo "Files after : $(ls /tmp/logs_demo | wc -l)"
rm -rf /tmp/logs_demo적절한 -P 값 선택
-P를 너무 낮게 설정하면 코어를 낭비하고, 너무 높게 설정하면 과도한 문맥 전환이 발생합니다. 시작점으로 논리 CPU 코어 수를 사용하는 것이 좋습니다.
- CPU 중심 작업(압축, 인코딩):
-P $(nproc) - 입출력 중심 작업(네트워크 호출, 디스크 읽기): 작업 프로세스가 대부분의 시간을 대기하므로
-P $(($(nproc) * 4))이상 - 메모리 제약이 있는 작업:
사용 가능한_RAM / 작업_RAM_사용량을 계산해 그 값으로 제한
nproc는 사용 가능한 처리 장치 수를 반환하므로, 하드코딩한 숫자를 대신할 수 있는 이식성 높은 방법입니다.
#!/usr/bin/env bash
CORES=$(nproc)
IO_WORKERS=$(( CORES * 4 ))
echo "CPU cores : $CORES"
echo "CPU-bound -P: $CORES"
echo "I/O-bound -P: $IO_WORKERS"
# Example: parallel curl downloads (I/O-bound)
# printf '%s\n' url1 url2 ... | xargs -n 1 -P "$IO_WORKERS" curl -sSO&를 사용하는 백그라운드 작업
작업별 오류 처리, 동적 목록 또는 복잡한 인수 구성이 필요해 xargs보다 더 세밀한 제어가 필요한 경우가 있습니다. 셸에 내장된 백그라운드 연산자 &를 사용해 작업을 직접 생성하십시오.
어떤 명령 뒤에든 &를 추가하면 제어권이 즉시 스크립트로 돌아옵니다. 부모 프로세스가 계속 실행되는 동안 자식 프로세스는 백그라운드에서 실행됩니다. 마지막에 wait를 호출하면 모든 자식 프로세스가 완료될 때까지 대기합니다.
#!/usr/bin/env bash
process() {
local id="$1"
sleep $(( RANDOM % 3 + 1 ))
echo "Job $id finished at $(date +%T)"
}
echo "Launching 5 background jobs..."
for id in $(seq 1 5); do
process "$id" &
done
wait # Block until every background job completes
echo "All jobs done."작업 풀로 동시 실행 제한
&를 사용해 모든 작업을 한꺼번에 생성하면 목록이 클 때 메모리가 고갈될 수 있습니다. 작업 풀은 언제든 최대 N개의 작업만 실행되도록 유지합니다.
- 각 작업을 생성한 후
jobs -r | wc -l로 현재 활성 상태인 백그라운드 작업 수를 확인합니다. - 개수가 한도에 도달하면
wait -n(Bash 4.3 이상)을 호출해 어떤 작업이든 하나 완료될 때까지 기다린 후 다음 작업을 생성합니다.
이 패턴은 xargs -P의 내부 동작을 모방하지만, 각 작업을 둘러싼 스크립트 로직을 완전히 자유롭게 작성할 수 있습니다.
#!/usr/bin/env bash
MAX_JOBS=3
process() {
local id="$1"
sleep $(( RANDOM % 3 + 1 ))
echo "Task $id done"
}
for id in $(seq 1 10); do
# Throttle: wait for a slot if pool is full
while (( $(jobs -r | wc -l) >= MAX_JOBS )); do
wait -n 2>/dev/null || true
done
process "$id" &
done
wait
echo "All 10 tasks complete."병렬 작업의 종료 코드 수집
백그라운드 작업에서는 다음 사항이 매우 중요합니다. 자식 프로세스가 실패해도 부모 스크립트가 이를 자동으로 알 수는 없습니다. 각 자식 프로세스의 PID를 수집하고 wait <pid>로 종료 상태를 확인해야 합니다.
아래 패턴에서는 모든 PID를 배열에 저장한 다음 배열을 순회하며 wait "$pid"를 호출합니다. 이 호출은 해당 자식 프로세스의 종료 코드를 반환합니다.
#!/usr/bin/env bash
set -euo pipefail
task() {
local id="$1"
sleep 1
if (( id == 3 )); then
echo "Task $id: FAILED" >&2
return 1
fi
echo "Task $id: ok"
}
pids=()
for id in $(seq 1 5); do
task "$id" &
pids+=("$!")
done
failed=0
for pid in "${pids[@]}"; do
if ! wait "$pid"; then
echo "PID $pid exited with error" >&2
(( failed++ ))
fi
done
(( failed == 0 )) && echo "All OK" || { echo "$failed job(s) failed"; exit 1; }xargs -P를 사용한 병렬 다운로드
네트워크 입출력은 높은 수준의 병렬 처리에 적합한 대표적인 사례입니다. 각 작업 프로세스가 대부분의 시간을 바이트를 기다리며 보내기 때문입니다. 아래 예제에서는 여러 URL을 동시에 가져와 각각을 고유한 이름의 파일로 저장합니다.
사용되는 주요 플래그는 다음과 같습니다.
-P 8— curl 프로세스 8개를 동시에 실행합니다.-n 1— curl 호출마다 URL 하나를 전달합니다.--create-dirs -o— curl이 파생된 파일 이름으로 저장합니다.
#!/usr/bin/env bash
# Download several small public files in parallel
URLs=(
"https://httpbin.org/bytes/1024"
"https://httpbin.org/bytes/2048"
"https://httpbin.org/bytes/512"
"https://httpbin.org/bytes/4096"
)
mkdir -p /tmp/parallel_dl
printf '%s\n' "${URLs[@]}" | xargs -n 1 -P 4 bash -c '
url="$1"
out="/tmp/parallel_dl/$(echo "$url" | md5sum | cut -c1-8).bin"
curl -sSf "$url" -o "$out" && echo "Saved $out"
' _
ls -lh /tmp/parallel_dl/
rm -rf /tmp/parallel_dlfind, xargs -P, 셸 함수 결합
여러 줄로 이루어진 셸 함수를 xargs와 함께 사용하려면 먼저 export -f function_name으로 내보낸 다음, xargs 내부에서 bash -c 'function_name "$@"' _를 통해 호출해야 합니다.
이 패턴을 사용하면 각 병렬 작업 프로세스 안에서 로깅, 오류 처리, 조건부 로직 등 강력한 스크립팅 기능을 항목별로 활용할 수 있습니다.
#!/usr/bin/env bash
mkdir -p /tmp/proc_demo
for i in $(seq 1 8); do echo "data $i" > /tmp/proc_demo/item_$i.txt; done
process_file() {
local f="$1"
local base
base=$(basename "$f" .txt)
# Simulate work: count words and append a timestamp
local wc
wc=$(wc -w < "$f")
echo "[$base] words=$wc processed=$(date +%T)" >> "/tmp/proc_demo/${base}.result"
}
export -f process_file
find /tmp/proc_demo -name '*.txt' -print0 \
| xargs -0 -n 1 -P "$(nproc)" bash -c 'process_file "$@"' _
grep '' /tmp/proc_demo/*.result
rm -rf /tmp/proc_demotime으로 성능 향상 측정
성능이 향상되었다고 주장하기 전에 항상 측정하십시오. 병렬 명령을 time으로 감싸 순차 실행 기준과 비교하십시오. 실제 성능 향상 정도는 다음 요인에 따라 달라집니다.
- 작업 독립성 — 잠금 없이 작업이 쓰기 가능한 상태를 공유해서는 안 됩니다.
- 오버헤드 — 작은 작업에서는 프로세스 생성 비용(각각 약 5~20ms)이 중요합니다.
- 리소스 경합 — CPU가 포화되기 전에도 디스크 입출력이 포화될 수 있습니다.
아래에 간단한 벤치마크 패턴이 나와 있습니다. 먼저 순차적으로 실행한 다음 병렬로 실행하고, real 실제 경과 시간을 비교하십시오.
#!/usr/bin/env bash
work() { sleep 0.2; } # simulate a 200ms task
export -f work
ITEMS=$(seq 1 16)
echo "=== Sequential ==="
time printf '%s\n' $ITEMS | xargs -n 1 bash -c 'work' _
echo
echo "=== Parallel ($(nproc) workers) ==="
time printf '%s\n' $ITEMS | xargs -n 1 -P "$(nproc)" bash -c 'work' _지식 점검: xargs -P 동작
xargs -P를 사용한 병렬 실행을 제대로 이해했는지 확인해 보십시오.
강의 요약
이제 Bash에서 병렬 실행을 수행하는 신뢰할 수 있는 두 가지 방법을 알게 되었습니다.
- xargs -n 1 -P N — 가장 간단한 방법입니다. xargs가 작업 프로세스 풀을 자동으로 관리합니다. 입력이 단순한 목록이고 각 항목이 하나의 명령에 대응할 때 가장 적합합니다.
- 백그라운드 작업(&) + wait — 스크립트를 완전히 제어할 수 있는 방법입니다. 작업별 PID, 동적 입력 또는 세밀한 종료 코드 처리가 필요할 때 필수적입니다. 동시 실행 수를 제한하려면 카운터와 함께
wait -n을 사용하십시오.
앞으로 기억해야 할 핵심 규칙은 다음과 같습니다.
xargs를 통해 전달하기 전에export -f로 셸 함수를 내보내십시오.- 공백이 포함된 파일 이름을 안전하게 처리하려면
-print0/-0을 사용하십시오. - 배열에 PID를 저장하고 각 PID에 대해 개별적으로
wait "$pid"를 호출하여 실패를 감지하십시오. time으로 벤치마크하십시오. 작업 오버헤드가 프로세스 생성 비용보다 클 때만 병렬 처리가 이득을 냅니다.- CPU 중심 작업에는
-P $(nproc)를 설정하고, 입출력 중심 작업에는 더 높은 배수를 사용하십시오.
자주 묻는 질문
“xargs -P와 백그라운드 작업을 활용한 병렬 처리” 강의는 무료인가요?
네 — “xargs -P와 백그라운드 작업을 활용한 병렬 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Linux Command Line & Bash Scripting Mastery 강의 전체를 잠금 해제할 수 있습니다. Linux Command Line & Bash Scripting Mastery 강의에는 총 4개의 강의가 포함되어 있습니다.
“xargs -P와 백그라운드 작업을 활용한 병렬 처리”에서 뭘 배우나요?
xargs 병렬 모드와 관리되는 백그라운드 작업 풀을 사용하여 독립적인 작업을 동시에 실행합니다. 브라우저에서 직접 실행하는 실습 코드로 Linux Command Line & Bash Scripting Mastery을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Linux Command Line & Bash Scripting Mastery을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Linux Command Line & Bash Scripting Mastery은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“xargs -P와 백그라운드 작업을 활용한 병렬 처리” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Linux Command Line & Bash Scripting Mastery 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Linux Command Line & Bash Scripting Mastery 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 스크립트 프로파일링 및 불필요한 서브셸 방지
- xargs -P와 백그라운드 작업을 활용한 병렬 처리
- GNU parallel을 활용한 작업 오케스트레이션
- 처리량을 높이는 스트리밍 파이프라인과 명명된 파이프