Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Por que o subprocess.Popen não está esperando até que o processo filho termine?


subprocess.Popen , quando instanciado, executa o programa. No entanto, ele não espera por ele - ele o dispara em segundo plano como se você tivesse digitado cmd & em uma concha. Portanto, no código acima, você definiu essencialmente uma condição de corrida - se as inserções puderem terminar a tempo, parecerá normal, mas se não, você obterá a saída inesperada. Você não está esperando por sua primeira run() 'd PID para terminar, você está simplesmente retornando seu Popen instância e continuando.

Não tenho certeza de como esse comportamento contradiz a documentação, porque existem alguns métodos muito claros no Popen que parecem indicar que não é esperado, como:
Popen.wait()
  Wait for child process to terminate. Set and return returncode attribute.

Concordo, no entanto, que a documentação para este módulo poderia ser melhorada.

Para esperar que o programa termine, recomendo usar subprocess método de conveniência de, subprocess.call , ou usando communicate em um Popen object (para o caso em que você precisa de stdout). Você já está fazendo isso para sua segunda chamada.
### START MAIN
# copy some rows from a source table to a destination table
# note that the destination table is empty when this script is run
cmd = 'mysql -u ve --skip-column-names --batch --execute="insert into destination (select * from source limit 100000)" test'
subprocess.call(cmd)

# check to see how many rows exist in the destination table
cmd = 'mysql -u ve --skip-column-names --batch --execute="select count(*) from destination" test'
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
try: count = (int(process.communicate()[0][:-1]))
except: count = 0

Além disso, na maioria dos casos, você não precisa executar o comando em um shell. Este é um desses casos, mas você terá que reescrever seu comando como uma sequência. Fazer dessa forma também permite que você evite a injeção de shell tradicional e se preocupe menos com citações, assim:
prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)

Isso até funcionará e não será injetado como você esperaria:
prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)

Experimente interativamente. Você evita as possibilidades de injeção de shell, principalmente se estiver aceitando a entrada do usuário. Suspeito que você esteja usando o método de string menos incrível de comunicação com o subprocesso porque teve problemas para fazer as sequências funcionarem :^)