Tenho dois scripts que usam GPU e treinam modelos de ML. Quero iniciá-los antes de dormir, para que funcionem à noite e espero ver alguns resultados pela manhã.
Mas como a memória da GPU é limitada, quero executá-los em série em vez de paralelo.
Eu posso fazer isso com python train_v1.py && python train_v2.py
; mas digamos que comecei a treinar o train_v1
. Nesse ínterim, como o treinamento é muito demorado, iniciei e terminei a implementação do segundo script, train_v2.py
e quero executá-lo automaticamente quando python train_v1.py
terminar.
Como posso conseguir isso? Obrigado.
Responder1
Aqui está uma abordagem que não envolve fazer loop e verificar se o outro processo ainda está ativo ou chamar train_v1.py
de uma maneira diferente do que você faria normalmente:
$ python train_v1.py
^Z
[1]+ Stopped python train_v1.py
$ % && python train_v2.py
Sou ^Z
eu pressionando Ctrl+ Zenquanto o processo está em hibernação, train_v1.py
enviando um SIGTSTP
sinal. Então, digo ao shell para ativá-lo com %
, usando-o como um comando ao qual posso adicionar o && python train_v2.py
no final. Isso faz com que ele se comporte como se você tivesse feito isso python train_v1.py && python train_v2.py
desde o início.
Em vez de %
, você também pode usar fg
. É a mesma coisa. Se quiser saber mais sobre esses tipos de recursos do shell, você pode ler sobre eles ema seção "JOB CONTROL" da página de manual do bash.
EDIT: Como continuar adicionando itens à fila
Conforme apontado por jamesdlin em um comentário, se você tentar continuar o padrão a ser adicionado, train_v3.py
por exemplo, antes do início da v2, descobrirá que não pode:
$ % && python train_v2.py
^Z
[1]+ Stopped python train_v1.py
Só train_v1.py
fica parado porque train_v2.py
ainda não começou, e você não pode parar/suspender/adormir algo que nem começou.
$ % && python train_v3.py
resultaria no mesmo que
python train_v1.py && python train_v3.py
porque %
corresponde ao último processo suspenso. Em vez de tentar adicionar v3
assim, deve-se usar o histórico:
$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py
Pode-se fazer a expansão do histórico como acima, ou recuperar o último comando com um atalho de teclado (como up) e adicionar v3 ao final.
$ % && python train_v2.py && python train_v3.py
Isso é algo que pode ser repetido para adicionar mais ao pipeline.
$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py
^Z
[1]+ Stopped python train_v1.py
$ !! && python train_v4.py
% && python train_v2.py && python train_v3.py && python train_v4.py
Responder2
Se você já iniciou python train_v1.py
, você poderia usar pgrep
para pesquisar esse processo até que ele desapareça e, em seguida, executar seu segundo script Python:
while pgrep -u "$USER" -fx 'python train_v1.py' >/dev/null
do
# sleep for a minute
sleep 60
done
python train_v2.py
Ao usar -f
e -x
você compara a linha de comando exata que foi usada para iniciar o primeiro script Python. Em alguns sistemas, pgrep
implementa uma -q
opção que o torna silencioso (assim como grep -q
), o que significa que o redirecionamento para /dev/null
não seria necessário.
A -u
opção restringe a correspondência aos comandos que você está executando (e não a um amigo ou outra pessoa no mesmo sistema).
Se você ainda não iniciou o primeiro script:
Conforme mencionado nos comentários, você poderia simplesmente iniciar o segundo script logo após o primeiro script. O fato de o segundo script não existir ou ainda não estar pronto para ser executado não importa (desde que esteja pronto para ser executado quando o primeiro script terminar):
python train_v1.py; python train_v2.py
Fazer dessa forma iniciará o segundo script, independentemente do status de saída do primeiro script. Usar &&
em vez de ;
, como você mostra na pergunta, também funcionará, mas exigirá que o primeiro script seja concluído com êxito para que o segundo script seja iniciado.
Responder3
Você pode iniciar o primeiro script com
python train_v1.py; touch finished
Depois basta fazer um loop que verifica regularmente se finished
existe:
while [ ! -f finished ] ; do
sleep 5
done
python train_v2.py
rm finished
Responder4
Se você não precisa saber o status de saída do primeiro script, recomendo algo comoo que Kusalananda escreveu.
Se você precisar saber o status de saída (o que provavelmente não é necessário neste caso, mas outra pessoa pode aparecer procurando uma solução que faça isso), é mais complicado. Eu escrevi umpequeno utilitário Linuxpwait
que permite aguardar a conclusão de um processo e descobrir seu status de saída.