Domanda perché python.subprocess si blocca dopo proc.communicate ()?


Ho chiamato un programma interattivo my_own_exe. Innanzitutto, stampa alive, quindi inserisci S\n e poi stampa alive ancora. Finalmente hai inserito L\n. Funziona ed esce.

Tuttavia, quando lo chiamo dal seguente script python, il programma sembrava bloccarsi dopo aver stampato il primo 'vivo'.

Qualcuno può dirmi perché questo sta accadendo?

// dopo aver letto i follow up (grazie ragazzi), ho modificato il codice come segue:

import subprocess
import time

base_command = "./AO_FelixStrategy_UnitTest --bats 31441 --chix 12467 --enxutp 31884 --turq 26372 --symbol SOGN --target_date " + '2009-Oct-16'
print base_command

proc2 = subprocess.Popen(base_command, shell=True , stdin=subprocess.PIPE,)

time.sleep(2);
print "aliv"
proc2.communicate('S\n')

print "alive"
time.sleep(6)

print "alive"
print proc2.communicate('L\n')
time.sleep(6)

il programma ora va bene con il primo input 'S \ n', ma poi si ferma, e io il secondo 'L \ n' è un po 'ignorato.

Qualcuno può darmi un'idea del perché è così?


12
2018-03-09 11:35


origine


risposte:


Dal documenti per communicate:

Interagisci con il processo: invia i dati a stdin. Leggi i dati da stdout e stderr, fino al raggiungimento della fine del file. Attendere il termine del processo.

Quindi dopo communicate() corre, il processo è stato terminata.

Se vuoi scrivere e leggere senza aspettare che il processo si fermi:

  • non mai uso shell=True - richiama inutilmente una shell per chiamare a sua volta il programma, quindi ci sarà un altro processo tra te e il tuo programma. Questo ha molti spiacevoli effetti collaterali. L'impostazione predefinita è shell=False quindi dovresti attenervisi. Cambia il tuo Popen linea a:

    p = subprocess.Popen(["./AO_FelixStrategy_UnitTest",
                          "--bats", "31441", "--chix", "12467",
                          "--enxutp", "31884", "--turq", "26372",
                          "--symbol", "SOGN", "--target_date", '2009-Oct-16'],
                         stdin=subprocess.PIPE, 
                         stdout=subprocess.PIPE)
    
  • Uso p.stdin.write scrivere al processo. Uso p.stdout.read leggere da esso.

  • chiamata p.stdout.read se non c'è nulla da leggere bloccherà. chiamata p.stdin.write se il buffer di scrittura è pieno si bloccherà. Quindi devi assicurarti di avere qualcosa da leggere / scrivere: lo fai su unix unix usando select. Su Windows, purtroppo, è necessario ricorrere ai thread. Almeno questo è ciò Popen.communicate fa internamente.
  • Se non hai scritto AO_FelixStrategy_UnitTest allora hai possibili problemi aggiuntivi:
    • Potrebbe essere la lettura da qualche altra parte, non lo standard input. Alcuni programmi leggono direttamente dal terminale, altri usano alcune API del sistema operativo per leggere. Ciò significa che i dati scritti su stdin non andranno al programma. Questo è spesso vero per i prompt della password.
    • Ricorda che devi rendere conto AO_FelixStrategy_UnitTest tamponi. Per impostazione predefinita, la comunicazione C PIPE standard viene memorizzata nel buffer in modo da non visualizzare alcun output fino a quando non si chiude il lato di input (facendo ciò p.stdin.close(). Salvo che AO_FelixStrategy_UnitTest scarica periodicamente l'output.

Ecco alcuni esempi di codice, in base a ciò che descrivi. Potrebbe funzionare a seconda di come AO_FelixStrategy_UnitTest è stato sviluppato:

p = subprocess.Popen(["./AO_FelixStrategy_UnitTest",
                      "--bats", "31441", "--chix", "12467",
                      "--enxutp", "31884", "--turq", "26372",
                      "--symbol", "SOGN", "--target_date", '2009-Oct-16'],
                     stdin=subprocess.PIPE, 
                     stdout=subprocess.PIPE)
output = p.communicate('S\nL\n')[0]
print output

25
2018-03-09 11:38



communicate() legge i dati da stdout e stderr fino alla fine del file. - Aspetta finché il tuo programma non si chiude.


3
2018-03-09 11:40



comunicare verrà eseguito una sola volta e quindi chiuderà la pipe, quindi se vuoi inviarti diversi comandi devi inviarne uno dopo l'altro nel file stessa stringa.

Ecco un esempio che ha funzionato per me dopo alcune indagini, cercando discussioni, sottoprocesso32, stdin.write, stdout.read ecc. Ecc. Queste informazioni non sono nelle informazioni di riferimento ufficiali di Python per comunicare: https://docs.python.org/2/library/subprocess.html

L'unico posto in cui ho trovato questo era qui: Il subprocesso Python comunica che uccide il mio processo

In ogni caso ecco il codice, semplice, senza discussioni, senza sottoprocesso32, funziona su linux e windows. Sì, devi sapere quante volte inviare comandi all'altro processo, ma in generale lo sai. Oltre a questo puoi aggiungere thread, cwd, shell = True o qualsiasi altra cosa tu voglia, ma questo è il caso più semplice:

def do_commands(self, cmd, parms):
    proc = subprocess.Popen(cmd,  stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE )

    # wait for the process to terminate
    out, err = process.communicate(cmd_parms)
    errcode = process.returncode

    return errcode, out, err

Ad esempio, se desideri inviare più ritorni a capo (\ n) all'applicazione che viene chiamata e il parametro a nel centro (a livello interattivo) chiamerai qualcosa del genere:

cmd_parms = "\n\n\n\n\nparm\n\n"

errcode, out, err = do_commands(command, cmd_parms)

1
2017-08-17 15:50