Eu tenho três tipos de dados que estão em formatos diferentes; para cada tipo de dado, existe um script Python que o transforma em um único formato unificado.
Esse script Python é lento e vinculado à CPU (para um único núcleo em uma máquina com vários núcleos), então eu quero executar três instâncias dele - uma para cada tipo de dados - e combinar sua saída para transmiti-la sort
. Basicamente, equivalente a isso:
{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n
Mas com os três scripts sendo executados em paralelo.
Eu encontrei essa pergunta em que o GNU split
estava sendo usado para alternar entre o fluxo stdout e as instâncias de um script que lida com o fluxo.
Na página do manual dividida:
-n, --number=CHUNKS
generate CHUNKS output files. See below
CHUNKS may be:
N split into N files based on size of input
K/N output Kth of N to stdout
l/N split into N files without splitting lines
l/K/N output Kth of N to stdout without splitting lines
r/N like 'l' but use round robin distributio
Portanto, o r/N
comando implica " sem dividir linhas ".
Com base nisso, parece que a seguinte solução deve ser viável:
split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF
Onde choose_script
é que isto:
#!/bin/bash
{ read x; ./handle_$x.py; }
Infelizmente, vejo algumas misturas de linhas - e muitas linhas novas que não deveriam estar lá.
Por exemplo, se eu substituir meus scripts Python por alguns scripts simples do bash que fazem isso:
#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;
.
#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;
.
#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;
Eu vejo esta saída:
1-8394
2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981
Isso é irritante - com base no extrato da página de manual que colei acima, ele deve manter a integridade da linha.
Obviamente funcionará se eu remover o -u
argumento, mas ele será armazenado em buffer e a memória ficará insuficiente, pois armazena em buffer a saída de todos os scripts, exceto um.
Se alguém tiver alguma ideia aqui, seria muito apreciada. Estou fora da minha profundidade aqui.
coproc
built-in no bash, embora eu realmente não veja como ele se aplica.job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3
?Respostas:
Tente usar a opção -u do GNU paralelo.
Isso os executa em paralelo, sem armazenar em buffer todo o processo.
fonte
X
deIX
dizer-I
que X será a bandeira para substituir ou está aplicando a-X
bandeira, que aparentemente também tem um significado relevante?parallel -u -X ./handle_{}.sh ::: "1" "2" "3"
:, e infelizmente ainda estou vendo alguma saída confusa.parallel -u ./handle_{}.sh
, mas eu prefiro alterá-lo, pois chaves também têm o significado de unir comandos (como na sua pergunta).Tentar:
Se
handle_1.py
leva um nome de arquivo:Você não deseja que a saída seja misturada, portanto, não use -u.
Se você deseja manter o pedido (toda a saída do handle_1 é anterior ao handle_2 e, portanto, você pode evitar a classificação):
Se você ainda deseja classificá-lo, pode paralelizar a classificação e utilizar
sort -m
:Defina $ TMPDIR como um diretório grande o suficiente para armazenar a saída.
fonte
Talvez esteja faltando alguma coisa, mas você não pode simplesmente fazer:
Se você deseja que as linhas de cada processo não sejam intercaladas, o mais fácil é provavelmente garantir que o próprio processo as escreva totalmente e possivelmente desative o buffer de saída, pois
write
s em um pipe são garantidos como atômicos, desde que não sejam maiores quePIPE_BUF
. Por exemplo, você pode ter certeza de que ele usa o buffer de saída à lastdio
e callfflush
ou qualquer que seja o equivalentepython
após uma ou poucas linhas serem gravadas.Se você não pode modificar os scripts python, você pode fazer:
(com GNU grep) ou:
(Veja as notas nos comentários abaixo se o que os comandos emitem não é texto)
E fazer:
Outra opção para evitar esses 3
lb
processos é ter três canais para um comando que useselect
/poll
para ver de onde vem alguma saída e alimentá-la comsort
base em linha, mas é preciso um pouco de programação.fonte
wait
lá, eu acho.sort -n
permanecerá até que todos os programas com um fd aberto tenham saído.A resposta do Flowbok foi a solução correta. Estranhamente, a saída do GNU
parallel
é alterada se for diretamente para um arquivo - mas não se for para um tty.Felizmente,
script -c
está disponível para imitar um tty.Ainda existem os três scripts:
.
.
Depois, há um arquivo que encapsula a chamada em paralelo:
E então eu chamo assim:
As linhas na saída são misturadas linha a linha entre a saída dos diferentes scripts, mas não são mutiladas ou intercaladas em uma determinada linha.
Comportamento bizarro de
parallel
- posso enviar um relatório de erro.fonte