Mysql
 sql >> Base de données >  >> RDS >> Mysql

Pourquoi subprocess.Popen n'attend-il pas que le processus enfant se termine ?

subprocess.Popen , lorsqu'il est instancié, exécute le programme. Cependant, il ne l'attend pas - il le déclenche en arrière-plan comme si vous aviez tapé cmd & dans une coquille. Ainsi, dans le code ci-dessus, vous avez essentiellement défini une condition de concurrence - si les insertions peuvent se terminer à temps, cela semblera normal, mais sinon, vous obtiendrez une sortie inattendue. Vous n'attendez pas votre premier run() 'd PID pour finir, vous renvoyez simplement son Popen instance et continuer.

Je ne sais pas en quoi ce comportement contredit la documentation, car il existe des méthodes très claires sur Popen qui semblent indiquer qu'il n'est pas attendu, comme :

Popen.wait()
  Wait for child process to terminate. Set and return returncode attribute.

Je suis cependant d'accord que la documentation de ce module pourrait être améliorée.

Pour attendre la fin du programme, je vous recommande d'utiliser subprocess la méthode pratique de , subprocess.call , ou en utilisant communicate sur un Popen objet (pour le cas où vous avez besoin de stdout). Vous faites déjà cela pour votre deuxième appel.

### 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

De plus, dans la plupart des cas, vous n'avez pas besoin d'exécuter la commande dans un shell. C'est l'un de ces cas, mais vous devrez réécrire votre commande comme une séquence. Le faire de cette façon vous permet également d'éviter l'injection de shell traditionnelle et de vous soucier moins des citations, comme ceci :

prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)

Cela fonctionnera même et n'injectera pas comme prévu :

prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)

Essayez-le de manière interactive. Vous évitez les possibilités d'injection de shell, en particulier si vous acceptez l'entrée de l'utilisateur. Je soupçonne que vous utilisez la méthode de chaîne moins géniale pour communiquer avec le sous-processus, car vous avez rencontré des difficultés pour faire fonctionner les séquences :^)