Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Dlaczego subprocess.Popen nie czeka na zakończenie procesu podrzędnego?

subprocess.Popen , po utworzeniu wystąpienia uruchamia program. Jednak nie czeka na to - uruchamia go w tle, tak jakbyś wpisał cmd & w powłoce. Tak więc w powyższym kodzie zasadniczo zdefiniowałeś sytuację wyścigu -- jeśli wstawki mogą zakończyć się na czas, będą wyglądać normalnie, ale jeśli nie, otrzymasz nieoczekiwane wyjście. Nie czekasz na swój pierwszy run() Jeśli PID się zakończy, po prostu zwracasz jego Popen wystąpienie i kontynuacja.

Nie jestem pewien, w jaki sposób to zachowanie jest sprzeczne z dokumentacją, ponieważ istnieje kilka bardzo jasnych metod na Popen, które wydają się wskazywać, że nie jest to oczekiwane, takie jak:

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

Zgadzam się jednak, że dokumentacja tego modułu może zostać ulepszona.

Aby poczekać na zakończenie programu, polecam użyć subprocess wygodna metoda, subprocess.call lub używając communicate na Popen obiekt (w przypadku, gdy potrzebujesz stdout). Robisz to już podczas drugiego połączenia.

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

Dodatkowo w większości przypadków nie trzeba uruchamiać polecenia w powłoce. To jeden z tych przypadków, ale będziesz musiał przepisać swoje polecenie jak sekwencję. Robienie tego w ten sposób pozwala również uniknąć tradycyjnego wstrzykiwania powłoki i mniej martwić się o cytowanie, na przykład:

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

To nawet zadziała i nie będzie wstrzykiwać zgodnie z oczekiwaniami:

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

Wypróbuj to interaktywnie. Unikasz możliwości wstrzykiwania powłoki, szczególnie jeśli akceptujesz dane wejściowe użytkownika. Podejrzewam, że używasz mniej niesamowitej metody łańcuchowej komunikowania się z podprocesem, ponieważ masz problemy z uruchomieniem sekwencji :^)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. dodaj wiele danych w pliku xml za pomocą PHP xmlwriter

  2. Zmienne MySQL przechowujące nazwę bazy danych

  3. array_agg() PostgreSQL i array_to_string w MySQL

  4. Jak stworzyć wydarzenie, które działa co 24 godziny?

  5. Ustawianie ścieżki klasy dla plików JAR