0Pricing
Linux Command Line & Bash Scripting Mastery · Aula

Paralelismo com xargs -P e tarefas em segundo plano

Execute tarefas independentes simultaneamente usando o modo paralelo do xargs e grupos gerenciados de tarefas em segundo plano.

Paralelismo com xargs -P e tarefas em segundo plano é uma aula grátis de Linux Command Line & Bash Scripting Mastery no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Linux Command Line & Bash Scripting Mastery, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

Por que a execução sequencial é lenta

Quando você executa comandos um após o outro em um script de shell, deixa os núcleos da CPU ociosos. Considere redimensionar 500 imagens: cada chamada a convert usa um núcleo, enquanto os outros sete ficam ociosos.

O paralelismo resolve isso distribuindo várias tarefas simultaneamente. Duas ferramentas principais do Bash facilitam esse trabalho:

  • xargs -P — distribui uma lista de entradas entre N processos de trabalho paralelos
  • tarefas em segundo plano (&) + wait — cria processos manualmente e aguarda sua conclusão

Esta lição aborda as duas opções para que você possa escolher a ferramenta adequada a cada situação.

Revisão dos conceitos básicos de xargs

Antes de adicionar paralelismo, relembre como xargs funciona. Ele lê itens da entrada padrão e os passa como argumentos para um comando.

O sinalizador -I {} permite colocar o item de entrada em qualquer posição da string de comando, não apenas no final.

O exemplo abaixo converte cada arquivo .txt para maiúsculas usando tr. Cada arquivo é processado individualmente (referência sequencial).

#!/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_demo

Introdução ao xargs -P

Adicione o sinalizador -P N ao xargs para executar até N processos em paralelo. O xargs gerencia automaticamente o conjunto de processos de trabalho — quando uma posição fica livre, o próximo item começa imediatamente.

  • -P 0 — cria tantos processos quanto o número de entradas (use com cuidado em listas grandes)
  • -P 4 — mantém no máximo 4 processos de trabalho em execução a qualquer momento
  • -n 1 — envia exatamente um item de entrada por processo invocado (sinalizador complementar comum)

Juntos, -n 1 -P 4 formam o padrão mais comum: um item por processo de trabalho, com quatro processos simultâneos.

#!/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 "$@"' _

Processamento paralelo de arquivos

Um caso de uso prático é compactar muitos arquivos de registro simultaneamente. Sem -P, cada chamada a gzip bloqueia a próxima. Com -P 8, até oito compactações são executadas ao mesmo tempo, utilizando todos os núcleos da CPU.

Observe como -n 1 garante que cada processo de trabalho paralelo receba exatamente um nome de arquivo — algo essencial quando os nomes podem conter espaços (combine com -d '\n' ou -print0 / -0 para maior segurança).

#!/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

Escolhendo o valor adequado para -P

Definir -P com um valor muito baixo desperdiça núcleos; com um valor muito alto, causa excesso de alternância entre processos. Um bom ponto de partida é o número de núcleos lógicos da CPU:

  • Tarefas limitadas pela CPU (compactação, codificação): -P $(nproc)
  • Tarefas limitadas por E/S (chamadas de rede, leituras de disco): -P $(($(nproc) * 4)) ou mais, pois os processos de trabalho passam a maior parte do tempo aguardando
  • Tarefas limitadas pela memória: calcule available_RAM / task_RAM_usage e limite o valor nesse ponto

nproc retorna o número de unidades de processamento disponíveis, funcionando como uma alternativa portátil a números definidos manualmente.

#!/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

Tarefas em segundo plano com &

Às vezes, você precisa de mais controle do que o xargs oferece — tratamento de erros por tarefa, listas dinâmicas ou formatos de argumentos complexos. Use o operador de segundo plano integrado ao shell & para criar tarefas manualmente.

Adicionar & a qualquer comando devolve imediatamente o controle ao script. O processo filho é executado em segundo plano enquanto o processo pai continua. Chame wait no final para bloquear a execução até que todos os processos filhos terminem.

#!/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."

Limitando a concorrência com um conjunto de tarefas

Criar todas as tarefas de uma só vez com & pode esgotar a memória quando a lista é grande. Um conjunto de tarefas mantém no máximo N tarefas em execução a qualquer momento:

  • Depois de criar cada tarefa, verifique quantas tarefas em segundo plano estão ativas usando jobs -r | wc -l
  • Se a contagem atingir o limite, chame wait -n (Bash 4.3+) para aguardar a conclusão de qualquer uma das tarefas antes de criar a próxima

Esse padrão imita o funcionamento interno de xargs -P, mas oferece flexibilidade total para criar scripts em torno de cada tarefa.

#!/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."

Capturando códigos de saída de tarefas paralelas

Uma preocupação importante com tarefas em segundo plano é que, se um processo filho falhar, o script pai não fica sabendo automaticamente. Você precisa capturar o PID de cada filho e verificar seu status de saída com wait <pid>.

O padrão abaixo armazena cada PID em uma matriz e, em seguida, percorre a matriz chamando wait "$pid", que retorna o código de saída desse filho específico.

#!/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; }

Downloads paralelos com xargs -P

A E/S de rede é um caso clássico para alto paralelismo — cada processo de trabalho passa a maior parte do tempo aguardando bytes. O exemplo abaixo busca várias URLs simultaneamente e salva cada uma em um arquivo com nome exclusivo.

Principais sinalizadores usados:

  • -P 8 — oito processos curl simultâneos
  • -n 1 — uma URL por invocação do curl
  • --create-dirs -o — o curl salva em um nome de arquivo derivado
#!/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_dl

Combinando find, xargs -P e funções do shell

Para usar uma função do shell com várias linhas com xargs, você precisa exportá-la com export -f function_name e, em seguida, invocá-la por meio de bash -c 'function_name "$@"' _ dentro do xargs.

Esse padrão permite aproveitar todo o poder dos scripts em cada processo de trabalho paralelo: registro de eventos, tratamento de erros e lógica condicional — tudo por item.

#!/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_demo

Medindo o ganho de velocidade com time

Sempre faça medições antes de afirmar que houve melhoria. Envolva o comando paralelo com time e compare-o com a referência sequencial. O ganho real de velocidade depende de:

  • Independência das tarefas — as tarefas não devem compartilhar estado gravável sem bloqueios
  • Custo adicional — o custo de criar um processo (cerca de 5 a 20 ms cada) é relevante para tarefas pequenas
  • Disputa por recursos — a E/S de disco pode atingir seu limite antes mesmo da CPU

Um padrão simples de referência é mostrado abaixo: execute primeiro de forma sequencial, depois em paralelo, e compare os tempos de relógio de parede 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' _

Verificação de conhecimentos: comportamento de xargs -P

Teste sua compreensão sobre a execução paralela com xargs -P.

Recapitulação da lição

Agora você dispõe de duas técnicas confiáveis para execução paralela no Bash:

  • xargs -n 1 -P N — a abordagem mais simples; o xargs gerencia automaticamente o conjunto de processos de trabalho. É melhor quando sua entrada é uma lista simples e cada item corresponde a um comando.
  • tarefas em segundo plano (&) + wait — oferece controle total sobre o script; é essencial quando você precisa dos PIDs de cada tarefa, de entradas dinâmicas ou de um tratamento detalhado dos códigos de saída. Use wait -n com um contador para limitar a concorrência.

Regras importantes para as próximas etapas:

  • Exporte as funções do shell com export -f antes de passá-las pelo xargs
  • Use -print0 / -0 para tratar com segurança nomes de arquivos que contenham espaços
  • Capture os PIDs em uma matriz e chame wait "$pid" individualmente para detectar falhas
  • Faça referências de desempenho com time — o paralelismo só é vantajoso quando o custo adicional da tarefa supera o custo de criar o processo
  • Defina -P $(nproc) para tarefas limitadas pela CPU e um múltiplo maior para cargas de trabalho limitadas por E/S

Perguntas Frequentes

A aula “Paralelismo com xargs -P e tarefas em segundo plano” é grátis?

Sim — o texto completo de “Paralelismo com xargs -P e tarefas em segundo plano” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Linux Command Line & Bash Scripting Mastery, atualize para CoddyKit PRO. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

O que vou aprender em “Paralelismo com xargs -P e tarefas em segundo plano”?

Execute tarefas independentes simultaneamente usando o modo paralelo do xargs e grupos gerenciados de tarefas em segundo plano. Você pratica Linux Command Line & Bash Scripting Mastery com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Linux Command Line & Bash Scripting Mastery?

Nenhuma experiência prévia é necessária. Linux Command Line & Bash Scripting Mastery no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Paralelismo com xargs -P e tarefas em segundo plano”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Linux Command Line & Bash Scripting Mastery?

Sim. Cada aula de Linux Command Line & Bash Scripting Mastery inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Criação de perfis de desempenho e prevenção de subshells inúteis
  2. Paralelismo com xargs -P e tarefas em segundo plano
  3. Orquestração de cargas de trabalho com GNU parallel
  4. Pipelines de transmissão e pipes nomeados para maior vazão
← Voltar para Linux Command Line & Bash Scripting Mastery