Como usar o processamento multi-thread em scripts bash

Conteúdo

gato brincando com fio

O agendamento multiencadeado sempre foi do interesse dos desenvolvedores para aumentar o desempenho do aplicativo e maximizar o uso de recursos.. Este guia irá apresentá-lo aos fundamentos da codificação Bash multithread.

O que é programação multiprocesso?

Uma imagem vale mais que mil palavras, e isso é válido quando se trata de mostrar a diferença entre programar um único (1) programação thread e multi-thread (> 1) na festa:

dormir 1
dormir 1 & dormir 1

(Ultimo comando) Um comando simples de dois fios de uma linha que irá executar dois processos de suspensão em paralelo, um no fundo

Nosso primeiro mini script de linha única ou configuração de agendamento multi-threaded não poderia ter sido mais simples; na linha de frente, dormimos um segundo usando o sleep 1 comando. Em relação ao usuário, um único thread estava executando um único sonho de um segundo.

Na segunda linha, temos dois comandos de suspensão de um segundo. Nós nos juntamos a eles usando um & separador, que não apenas atua como um separador entre os dois sleep comandos, mas também como um prompt Bash para iniciar o primeiro comando em um thread de segundo plano.

Regularmente, alguém terminaria um comando usando um ponto e vírgula (;). Ao fazer isso, o comando seria executado e só então seria passado para o próximo comando que aparecer após o ponto-e-vírgula. Como um exemplo, correndo sleep 1; sleep 1 levaria pouco mais de dois segundos: exatamente um segundo para o primeiro comando, um segundo para o segundo e uma pequena quantidade de sobrecarga do sistema para cada um dos dois comandos.

Apesar disto, em vez de terminar um comando com um ponto e vírgula, você pode usar outros terminadores de comando que o Bash reconhece como &, && e ||. a && sintaxe não tem nada a ver com programação multithread, apenas faça isso; prossiga com a execução do segundo comando apenas se o primeiro comando foi bem sucedido. a || É o oposto de && e irá executar o segundo comando apenas se o primeiro comando falhar.

Voltando à programação multithread, usando & já que nosso terminador de comando iniciará um procedimento em segundo plano executando o comando que o precede. Em seguida, ele executa imediatamente o seguinte comando no shell atual, enquanto permite que o procedimento em segundo plano (hilo) correr sozinho.

Na saída do comando, podemos ver que um procedimento está sendo iniciado em segundo plano (como indicado [1] 445317 Onde 445317 é o ID do procedimento ou PID do procedimento de segundo plano recém-iniciado, e [1] é declarado que este é o nosso primeiro procedimento de fundo) e, posteriormente, terminou (como indicado [1]+ Done sleep 1).

Se você quiser ver um exemplo adicional de manipulação de processos de fundo, veja nosso post Bash Automation e Scripting Basics (Papel 3). Ao mesmo tempo, Truques de término do procedimento de bash podem ser de interesse.

Agora vamos mostrar que estamos realmente executando dois sleep processos ao mesmo tempo:

hora de dormir 1; echo 'done'
time $(dormir 1 & dormir 1); eco 'feito'

Executar dois fios de suspensão em paralelo, com um em segundo plano, usando uma subcamada

Aqui começamos nosso sleep procedimento baixo time e podemos ver como o nosso comando single threaded funcionou exatamente para 1.003 segundos antes do prompt da linha de comando ser retornado.

Apesar disto, no segundo exemplo, levou quase o mesmo tempo (1,005 segundos) embora estivéssemos executando dois períodos (e processos) suspensão, mesmo que não consecutivamente. Novamente usamos um procedimento em segundo plano para o primeiro comando de suspensão, levando a uma execução (semi) paralelo, Em outras palavras, multiproceso.

Também usamos um contêiner de subcamada ($(...)) em torno de nossos dois comandos de sonho para combiná-los sob time. Como podemos ver nosso done a saída é mostrada em 1.005 segundos e, por isso, os dois sleep 1 os comandos devem ter sido executados simultaneamente. Interessante é o aumento muito pequeno no tempo total de processamento (0,002 segundos) que pode ser facilmente explicado pelo tempo que leva para iniciar uma subcamada e o tempo que leva para iniciar um procedimento em segundo plano.

Gerenciando processos multi-threaded (e no fundo)

Na festa, a codificação multi-thread envolverá regularmente threads de fundo de um script principal de uma linha ou um script bash completo. Em essência, pode-se pensar na codificação multithread no Bash como o início de vários threads de fundo. Quando alguém começa a codificar usando vários threads, rapidamente se torna claro que tais threads geralmente requerem algum manuseio. Como um exemplo, tome o exemplo fictício em que começamos cinco períodos simultâneos (e processos) de sono em um script Bash;

#!/bin/bash

sleep 10 & 
dormir 600 & 
dormir 1200 & 
dormir 1800 & 
dormir 3600 &

Executando cinco segmentos paralelos de suspensão em segundo plano a partir de um script

Quando começarmos o roteiro (depois de torná-lo executável usando chmod +x rest.sh), Não vemos nenhuma saída!! Mesmo que corramos jobs (o comando que exibe os trabalhos de fundo em andamento), nenhuma saída. Por que?

A razão é que a concha que foi usada para iniciar este script (Em outras palavras, a concha atual) não é a mesma concha (nem o mesmo fio; para começar a pensar em termos de subcamadas como fios em e de si mesmos) quem executou o sonho real. comandos ou colocados em segundo plano. Foi bastante o (sub) concha que começou quando ./rest.sh foi executado.

Vamos mudar nosso script adicionando jobs dentro do script. Isso irá garantir que jobs corre de dentro do (sub) concha onde for relevante, o mesmo em que os períodos começaram (e processos) do sonho.

Adicionar comando de jobs no script

Desta vez, podemos ver a lista de processos em segundo plano que estão começando graças a jobs comando no final do script. Também podemos ver seus PIDs (identificadores de procedimento). Esses PIDs são muito importantes quando se trata de lidar e gerenciar processos em segundo plano.

Outra maneira de obter o ID do procedimento em segundo plano é consultá-lo imediatamente após colocar um programa / procedimento de fundo:

#!/bin/bash

sleep 10 & 
eco ${!}
dormir 600 & 
eco ${!}
dormir 1200 & 
eco ${!}
dormir 1800 & 
eco ${!}
dormir 3600 &
eco ${!}

Consulte o PID (Id de processo) do último processo em segundo plano a ser iniciado com $ {!}

Semelhante ao nosso jobs comando (com novos PIDs agora, quando reiniciarmos nosso rest.sh roteiro), graças à festa ${!} Quando a variável é repetida, agora veremos que todos os cinco PIDs são exibidos quase imediatamente após o início do script: vários processos de suspensão foram colocados em threads de fundo, um após o outro.

The wait Command

Uma vez que iniciamos nossos processos de background, não temos mais nada a fazer a não ser esperar que eles terminem. Apesar disto, quando cada procedimento em segundo plano está executando uma subtarefa complexa, e precisamos do script principal (que iniciou os processos em segundo plano) retomar a execução quando um ou mais dos processos em segundo plano forem encerrados, precisamos de código adicional para lidar com isso.

Vamos expandir nosso script agora com o wait comando para lidar com nossos tópicos de fundo:

#!/bin/bash

sleep 10 & 
T1 = ${!}
dormir 600 & 
T2 = ${!}
dormir 1200 & 
T3 = ${!}
dormir 1800 & 
T4 = ${!}
dormir 3600 &
T5 = ${!}

eco "Este script começou 5 threads de fundo que estão atualmente em execução com PIDs ${T1}, ${T2}, ${T3}, ${T4}, ${T5}."
esperar ${T1}
eco "Fio 1 (dormir 10) com PID ${T1} terminou!"
esperar ${T2}
eco "Fio 2 (dormir 600) com PID ${T2} terminou!"

Aqui, estendemos nosso roteiro com dois wait comandos que aguardam o PID anexado ao primeiro e segundo threads terminar. Depois de 10 segundos, nosso primeiro tópico existe e somos notificados sobre ele. Passo a passo, este script fará o seguinte: inicie cinco tópicos quase ao mesmo tempo (mesmo que o início dos threads em si ainda seja sequencial e não paralelo) onde cada um dos cinco sleepvai correr em paralelo.

Depois de, os relatórios do script principal (sequencialmente) sobre o tópico criado e, subseqüentemente, aguarde até que o id do procedimento do primeiro thread termine. Quando isso acontecer, irá relatar sequencialmente no final do primeiro tópico e começar a esperar que o segundo tópico termine, etc.

Usando expressões idiomáticas bash &, ${!} e ele wait O comando nos dá grande flexibilidade quando se trata de executar vários threads em paralelo (como tópicos de fundo) na festa.

Final

Neste post, Exploramos os fundamentos do script Bash multithread. Introduziu o operador de procedimento em segundo plano (&) usando alguns exemplos fáceis de seguir, mostrando tanto single threaded quanto multi threaded sleep comandos. A seguir, discutimos como lidar com processos em segundo plano por meio de expressões idiomáticas bash comumente usadas. ${!} e wait. Nós também exploramos o jobs comando para ver a execução do thread / processos de fundo.

Se você gostou de ler este post, dê uma olhada em nossos Hacks de rescisão de procedimento pós-Bash.

Assine a nossa newsletter

Nós não enviaremos SPAM para você. Nós odiamos isso tanto quanto você.