GNU Parallel: xargs를 넘어선 강력한 병렬 처리
작성일:
리눅스 환경에서 대량의 데이터나 파일을 처리하다 보면, 단일 코어만 사용하는 쉘 스크립트의 성능 한계에 부딪히게 됩니다. xargs를 통해 어느 정도 병렬 처리가 가능하지만, 더 복잡하고 강력한 기능을 제공하는 도구가 바로 GNU Parallel입니다.
🚀 parallel 개요
GNU Parallel은 로컬 또는 원격 컴퓨터에서 작업을 병렬로 실행하기 위한 쉘 도구입니다. 덴마크의 Ole Tange가 Perl로 개발했으며, 표준 입력(stdin)이나 파일로부터 인자를 받아 명령어를 병렬로 실행합니다.
가장 큰 특징은 xargs나 find -exec와 같은 기존 도구들의 사용성을 유지하면서도, 출력 제어, 작업 슬롯 관리, 원격 실행 등 고급 기능을 제공한다는 점입니다.
⚙️ 주요 기능 및 내부 구현
1. 출력 그룹화 (Output Grouping)
병렬 처리 시 가장 큰 골칫거리 중 하나는 여러 프로세스의 출력이 뒤섞이는 것입니다.
xargs -P를 사용하면 여러 줄의 출력이 섞여서 알아보기 힘든 경우가 많습니다.- Parallel은 각 작업의 출력을 임시 파일이나 메모리에 버퍼링했다가, 작업이 완료되는 순간 한꺼번에 출력합니다. 따라서 출력이 섞이지 않고 깔끔하게 보장됩니다.
2. 지능적인 작업 슬롯 관리
parallel은 기본적으로 시스템의 CPU 코어 수를 감지하여 최적의 병렬 작업 수(Job slot)를 결정합니다.--load옵션을 통해 시스템 부하(Load Average)에 따라 새로운 작업을 시작할지 대기할지 동적으로 결정할 수도 있습니다.
3. 강력한 인자 치환 (Replacement Strings)
xargs보다 훨씬 유연한 인자 치환 기능을 제공합니다.
{}: 전체 인자 (기본값){.}: 확장자를 제외한 파일명 (file.txt->file){/}: 경로를 제외한 파일명 (Basename,dir/file.txt->file.txt){//}: 파일명을 제외한 경로 (Dirname,dir/file.txt->dir){/.}: 경로와 확장자를 모두 제외한 순수 파일명 (dir/file.txt->file){#}: 작업의 시퀀스 번호 (1부터 시작){%}: 작업 슬롯 번호 (1 ~ 병렬 작업 수){n}: n번째 입력 소스의 인자 (예:{1},{2}-:::또는::::사용 시)
4. Perl 기반 구현
GNU Parallel은 단일 Perl 스크립트로 구현되어 있습니다. 이는 별도의 컴파일 과정 없이 Perl이 설치된 대부분의 유닉스/리눅스 시스템에서 즉시 사용할 수 있음을 의미합니다.
🎛️ 주요 옵션 (Major Options)
parallel은 매우 방대한 옵션을 제공하지만, 자주 사용되는 핵심 옵션들은 다음과 같습니다.
--jobs N/-j N: 동시에 실행할 작업(Job)의 개수를 지정합니다. (기본값: CPU 코어 수)+N: 코어 수 + N개-N: 코어 수 - N개50%: 코어 수의 50%
--load N/-l N: 시스템 부하(Load Average)가 N 이상이면 새 작업을 시작하지 않고 대기합니다.--delay N: 각 작업 시작 사이에 N초의 지연 시간을 둡니다. (API 호출 제한 등에 유용)--timeout N: 작업이 N초 이상 걸리면 강제로 종료합니다.--joblog FILE: 작업 실행 기록(Exit code, 실행 시간 등)을 파일에 저장합니다.--resume:--joblog를 사용하여 중단된 작업 지점부터 다시 시작합니다.--bar: 진행 상황을 프로그레스 바 형태로 보여줍니다.--dry-run: 명령어를 실제로 실행하지 않고, 실행될 명령어 구문을 출력합니다.--keep-order/-k: 작업 완료 순서와 상관없이, 입력 순서대로 출력을 정렬합니다.--pipe: 표준 입력을 덩어리(Block)로 나누어 여러 작업으로 분산 처리합니다. (대용량 파일 처리에 필수)--block N:--pipe사용 시 나눌 블록의 크기를 지정합니다. (예:10M,1G)--tag: 각 출력 라인의 앞에 인자를 태그로 붙여서 어떤 작업의 결과인지 식별하게 해줍니다.--colsep regexp: 입력 라인을 정규표현식 구분자로 나누어{1},{2}, … 로 사용할 수 있게 합니다. (예:--colsep ','- CSV 처리)
🆚 xargs와의 비교
| 특징 | GNU Parallel | xargs (-P 옵션) |
|---|---|---|
| 출력 순서 | 작업 단위로 그룹화되어 섞이지 않음 | 라인 단위로 섞일 수 있음 (Interleaved) |
| 사용 편의성 | 직관적이고 다양한 치환 문자 제공 ({.}, {/} 등) |
비교적 제한적 (-I {} 등) |
| 원격 실행 | SSH를 통한 손쉬운 분산 처리 지원 (-S) |
기본 지원 없음 (별도 구현 필요) |
| 입력 처리 | 빈 칸, 따옴표 등 특수 문자 처리가 강력함 | 특수 문자 처리가 까다로울 수 있음 (-0 필요) |
| 성능 | Perl 오버헤드가 약간 있음 (작업당 수 ms) | C로 구현되어 매우 가벼움 |
Note: 수백만 개의 아주 짧은 작업(ms 단위)을 실행할 때는
xargs가 더 빠를 수 있지만, 대부분의 실무 작업(초 단위 이상)에서는parallel의 오버헤드는 무시할 만하며 편의성이 압도적입니다.
💻 샘플 명령어 10선
1. 기본 사용법: 파일 압축하기 (Basic)
현재 디렉토리의 모든 *.log 파일을 gzip으로 병렬 압축합니다.
ls *.log | parallel gzip
- 기본 동작: 파이프(
|)로 전달된 표준 입력의 각 라인을 인자로 받아gzip명령어를 병렬 실행합니다. - 별도 옵션이 없으면 CPU 코어 수만큼의 작업이 동시에 실행됩니다.
2. 인자 치환 활용: 이미지 변환 (Image Processing)
images 폴더의 모든 .jpg 파일을 .png로 변환하여 converted 폴더에 저장합니다.
ls images/*.jpg | parallel convert {} converted/{/.}.png
{}: 입력 파일 전체 경로 (images/photo.jpg){/.}: 경로와 확장자를 제외한 파일명 (photo)
3. 여러 인자 조합하기 (Cartesian Product)
여러 리스트의 모든 조합을 실행할 때 매우 유용합니다. :::, :::: 구분자를 사용합니다.
parallel echo "Color: {1}, Size: {2}" ::: Red Blue Green ::: S M L
:::: 커맨드 라인 인자로 리스트를 전달할 때 사용합니다.{1},{2}: 첫 번째, 두 번째 리스트의 인자를 각각 참조합니다.
파일로부터 인자를 읽어올 때는 ::::를 사용합니다.
# userlist.txt와 hostlist.txt의 모든 조합 실행
parallel echo "User: {1}, Host: {2}" :::: userlist.txt :::: hostlist.txt
::::: 파일의 내용을 인자 리스트로 사용할 때 사용합니다. 각 파일의 라인들이 조합됩니다.
4. 원격 서버 분산 처리 (Remote Execution)
로컬의 파일을 여러 서버로 전송하지 않고, 명령어만 분산 실행합니다. (SSH 설정 필요)
# server1, server2에서 hostname 실행
parallel --nonall -S server1,server2 hostname
--nonall: 인자를 전달하지 않고, 모든 서버에서 명령어를 한 번씩만 실행합니다.-S server1,server2: 작업을 실행할 원격 서버 목록을 지정합니다. (콤마로 구분)
5. 대량 파일 다운로드 (Multiple URL Download)
urls.txt에 있는 수많은 URL을 4개의 작업으로 병렬 다운로드합니다.
cat urls.txt | parallel -j 4 wget {}
-j 4: 동시에 실행할 작업 수를 4개로 고정합니다. (서버 부하 조절 시 유용)
6. 대규모 문자열 검색 (Large Scale Grep)
수만 개의 파일에서 특정 문자열을 검색할 때 grep 하나로는 느릴 수 있습니다.
find . -name "*.txt" | parallel grep "pattern" {}
find와 조합하여 재귀적으로 파일을 찾고,grep을 병렬로 수행하여 검색 속도를 높입니다.
7. 동영상 변환 (Video Transcoding)
ffmpeg를 사용하여 여러 동영상 파일을 동시에 변환합니다. CPU를 많이 쓰는 작업에 효과적입니다.
ls *.mp4 | parallel ffmpeg -i {} -c:v libx264 output/{.}.mkv
{.}: 입력 파일명에서 확장자를 제거합니다. (video.mp4->video)- CPU 집약적인 작업에서
parallel의 진가가 발휘됩니다.
8. 데이터베이스 쿼리 병렬 실행 (Database Processing)
여러 테이블이나 데이터베이스에 대해 SQL 쿼리를 병렬로 수행합니다.
cat tables.txt | parallel "mysql -e 'CHECK TABLE {};'"
- 명령어 전체를 따옴표(
")로 감싸서 복잡한 구문을 하나의 명령어로 전달합니다. {}가 SQL 쿼리 내부의 테이블명으로 치환됩니다.
9. 진행 상황 및 로그 기록 (Progress Bar & Job Log)
오래 걸리는 작업의 진행 상황을 확인하고, 결과를 로그로 남깁니다.
seq 100 | parallel --bar --joblog my_jobs.log sleep {}
--bar: 터미널 하단에 진행률(Progress Bar)을 표시합니다.--joblog my_jobs.log: 각 작업의 실행 결과(성공/실패, 소요 시간 등)를 로그 파일에 기록합니다.
10. 실패 시 재시도 (Fail/Retry Handling)
네트워크 불안정 등으로 작업이 실패할 경우 자동으로 재시도하게 할 수 있습니다.
# 실패 시 3번까지 재시도
cat urls.txt | parallel --retries 3 wget {}
--retries 3: 작업이 실패(Exit code != 0)할 경우, 최대 3번까지 재시도합니다.
11. CSV/TSV 데이터 처리 (Column Separation)
CSV나 TSV 같은 구분자가 있는 데이터를 처리할 때 --colsep을 사용하면 각 컬럼을 개별 인자로 사용할 수 있습니다.
# data.csv: name,age,email
# Alice,30,alice@example.com
cat data.csv | parallel --colsep ',' echo "Name: {1}, Age: {2}, Email: {3}"
--colsep ',': 쉼표(,)를 구분자로 사용하여 입력 라인을 분리합니다.- 분리된 각 컬럼은
{1},{2},{3}… 순서대로 접근할 수 있습니다. 탭 구분자 파일(TSV)의 경우--colsep '\t'를 사용합니다.
📝 결론
GNU Parallel은 단순한 병렬 실행 도구를 넘어, 복잡한 배치 작업을 효율적으로 처리할 수 있게 해주는 “Swiss Army Knife”와 같습니다. 특히 데이터 처리 파이프라인이나 시스템 관리 스크립트에서 xargs의 한계를 느꼈다면, 꼭 도입해 보시기를 추천합니다.
댓글남기기