Parallel

Para execução de scripts e programas, de forma paralela, em um sistema GNU/Linux, pode ser utilizado o GNU Parallel. Uma aplicação que permite distribuir a carga de procesamento, de uma ou várias aplicações, em múltiplos CPUs.

Instalação

No Ubuntu/Debian é possível fazer a instalação do seu pacote através dos reposítorios oficiais:

1
2
$ sudo apt-get get update
$ sudo apt-get install parallel

Sintaxe

Executada a instalação, é possível testar
sua utilização com comandos básicos. Dentre as diversas possibilidades de utilização do parallel (man parallel), uma das sintaxes mais simples de ser utilizada é a composição com :::. O trio de dois pontos consecutivos permite a indicação de comandos ou parâmetros que serão paralelizados.

No exemplo abaixo, o comando echo será paralelizado para exibição de dois parâmetros, a e b, simultaneamente.

1
$ parallel echo ::: a b

O retorno dessa execução deve ser:

1
2
a
b

Uma segunda forma de utilizar os ::: para criar comandos do parallel é indicando quais comandos devem ser paralelizados. Para este caso todos os parâmetros necessásios de cada comando serão inseridos num mesmo bloco, delimitado por aspas "".

1
2
$ parallel ::: "comando1 -parametros" "comando2 -parametros"

Dessa forma, os comandos 1 e 2 serão executados simultaneamente, independentes se são iguais ou possuem os mesmos parâmetros.

Exemplos

Uma forma de avaliar a execução simultânea dos comandos é mostrar o horário em que eles começaram a ser executados. Para verificar esse ponto serão utilizados em conjunto os comandos date e ping, em execuções paralelas e buscando sites distintos

Execução 1: date; ping -c 3 facebook.com

Execução 2 date; ping -c 3 google.com

1
$ parallel -k ::: "date; ping -c 3 facebook.com" "date; ping -c 3 google.com"

O parâmetro -k serve apenas para ordenar a exibição dos resultados de cada execução. Os sites indicados são apenas para testes, poderiam ser quaisquer outros acessíveis no momento.

Os resultados das execuções devem ser algo do tipo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sat May 16 19:22:37 -03 2020
PING facebook.com (31.13.85.36): 56 data bytes
64 bytes from 31.13.85.36: icmp_seq=0 ttl=49 time=22.865 ms
64 bytes from 31.13.85.36: icmp_seq=1 ttl=49 time=22.964 ms
64 bytes from 31.13.85.36: icmp_seq=2 ttl=49 time=23.001 ms
--- facebook.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 22.865/22.943/23.001/0.057 ms
Sat May 16 19:22:37 -03 2020
PING google.com (172.217.29.46): 56 data bytes
64 bytes from 172.217.29.46: icmp_seq=0 ttl=43 time=24.132 ms
64 bytes from 172.217.29.46: icmp_seq=1 ttl=43 time=24.155 ms
64 bytes from 172.217.29.46: icmp_seq=2 ttl=43 time=24.048 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 24.048/24.112/24.155/0.046 ms

É importante reparar o carimbo de hora indicado, pois é justamente ele que demonstra a execução paralela de cada uma das execuções:

1
Sat May 16 19:22:37 -03 2020

Aprofundamentos

A execução paralela tem a vantagem de permitir que diferentes programas sejam iniciados em conjunto, e mesmo que possuam tempo de execuções distintos, elas não interferirão entre si.

Serialização x Paralelização

Um exemplo oposto à paralelização é a execução em série. Os mesmos comandos poderiam ser dispostos em série, com objetivos de realizar as mesmas tarefas, porém os tempos de execuções não seriam os mesmos.

1
$ date && ping -c 3 facebook.com && date && ping -c 3 google.com
Resultado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sat May 16 20:03:08 -03 2020
PING facebook.com (157.240.222.35): 56 data bytes
64 bytes from 157.240.222.35: icmp_seq=0 ttl=49 time=14.406 ms
64 bytes from 157.240.222.35: icmp_seq=1 ttl=49 time=14.140 ms
64 bytes from 157.240.222.35: icmp_seq=2 ttl=49 time=14.014 ms
--- facebook.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 14.014/14.187/14.406/0.163 ms
Sat May 16 20:03:10 -03 2020
PING google.com (172.217.29.46): 56 data bytes
64 bytes from 172.217.29.46: icmp_seq=0 ttl=43 time=25.128 ms
64 bytes from 172.217.29.46: icmp_seq=1 ttl=43 time=24.595 ms
64 bytes from 172.217.29.46: icmp_seq=2 ttl=43 time=24.572 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 24.572/24.765/25.128/0.257 ms

Repare como cada execução do ping aconteceu em tempos distintos:

1
2
3
Execução 1: Sat May 16 20:03:08 -03 2020

Execução 2: Sat May 16 20:03:10 -03 2020

Com a ajuda do comando time, é possível repetir os cenários e aprofundar na comparação do tempo de execução de cada um dos cenários.

Cenário 1: Mensurando o tempo de execução da paralelização

1
$ time parallel -k ::: "date; ping -c 3 facebook.com" "date; ping -c 3 google.com"
Resultado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Sat May 16 20:52:58 -03 2020
PING facebook.com (157.240.222.35): 56 data bytes
64 bytes from 157.240.222.35: icmp_seq=0 ttl=49 time=14.108 ms
64 bytes from 157.240.222.35: icmp_seq=1 ttl=49 time=13.892 ms
64 bytes from 157.240.222.35: icmp_seq=2 ttl=49 time=13.811 ms
--- facebook.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 13.811/13.937/14.108/0.125 ms
Sat May 16 20:52:58 -03 2020
PING google.com (172.217.29.46): 56 data bytes
64 bytes from 172.217.29.46: icmp_seq=0 ttl=43 time=24.248 ms
64 bytes from 172.217.29.46: icmp_seq=1 ttl=43 time=23.609 ms
64 bytes from 172.217.29.46: icmp_seq=2 ttl=43 time=24.277 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 23.609/24.045/24.277/0.308 ms

real 0m2.159s
user 0m0.100s
sys 0m0.020s

Cenário 2: Mensurando o tempo de execução da serialização

1
time (date && ping -c 3 facebook.com && date && ping -c 3 google.com)
Resultado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Sat May 16 20:53:02 -03 2020
PING facebook.com (157.240.222.35): 56 data bytes
64 bytes from 157.240.222.35: icmp_seq=0 ttl=49 time=13.868 ms
64 bytes from 157.240.222.35: icmp_seq=1 ttl=49 time=13.860 ms
64 bytes from 157.240.222.35: icmp_seq=2 ttl=49 time=14.212 ms
--- facebook.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 13.860/13.980/14.212/0.164 ms
Sat May 16 20:53:04 -03 2020
PING google.com (172.217.29.46): 56 data bytes
64 bytes from 172.217.29.46: icmp_seq=0 ttl=43 time=24.081 ms
64 bytes from 172.217.29.46: icmp_seq=1 ttl=43 time=24.015 ms
64 bytes from 172.217.29.46: icmp_seq=2 ttl=43 time=24.933 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 24.015/24.343/24.933/0.418 ms

real 0m4.051s
user 0m0.000s
sys 0m0.000s
Comparativos:
1
2
Tempo de execução com paralelização: 0m2.159s
Tempo de execução com serialização: 0m4.051s

Desta forma, ficam demonstradas e exemplificadas as vantagens de se utilizar o parallel em rotinas repetitivas e/ou com tempos de execuções distintos.

Execução de um script scanner de rede com parallel:

prips 192.168.0.1/24 | parallel --timeout 2 -j0 'ping -c 1 {} >/dev/null && echo {}' 2>/dev/null

References