Tengo un problema con el método de Subprocess.Popen de Python.¿Por qué el subproceso.Popen no espera hasta que termina el proceso secundario?
Aquí hay una secuencia de comandos de prueba que demuestra el problema. Se está ejecutando en una caja de Linux.
#!/usr/bin/env python
import subprocess
import time
def run(cmd):
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
return p
### 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'
run(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 = run(cmd)
count = (int(process.communicate()[0][:-1]))
# if subprocess.Popen() waited for the child to terminate than count should be
# greater than 0
if count > 0:
print "success: " + str(count)
else:
print "failure: " + str(count)
time.sleep(5)
# find out how many rows exists in the destination table after sleeping
process = run(cmd)
count = (int(process.communicate()[0][:-1]))
print "after sleeping the count is " + str(count)
Por lo general, la salida de este script es:
success: 100000
pero a veces es
failure: 0
after sleeping the count is 100000
Tenga en cuenta que en el caso de fallo, el selecto inmediatamente después de la inserción muestra 0 filas, pero después Dormir durante 5 segundos por segundo selecciona correctamente muestra un recuento de filas de 100000. Mi conclusión es que uno de los siguientes es verdadero:
- subprocess.Popen no está esperando que el hilo hijo a finalizar - Esto parece contradecir la documentación
- el inserto de MySQL no es atómico - mi comprensión de MySQL parece indicar inserción es atómica
- el selecto no es ver el recuento de filas correcto de inmediato - de acuerdo con un amigo que conoce mysql mejor que yo, esto no debería suceder tampoco
¿Qué me falta?
FYI, soy consciente de que esta es una forma hacky de interactuar con mysql desde Python y MySQLdb probablemente no tenga este problema, pero tengo curiosidad de por qué este método no funciona.
Gracias a todos por las grandes respuestas. Mirando de nuevo la documentación del subproceso, veo que el comentario "Espere a que termine el comando" aparece en las secciones de métodos de conveniencia, no en la sección del método de Popen. Asentí con la cabeza a la respuesta de Jed ya que respondió mejor a mi pregunta original, aunque creo que usaré la solución de Paul para mis futuras necesidades de scripting. –
Tenga en cuenta que os.system (a menos que haga algo más con él) devuelve el VALOR DEVUELTO del proceso (generalmente 0 o 1). No dejes que te muerda tampoco. –