Wie kann ich herausfinden, wann der Subprozess nach Verwendung von os.kill () beendet wurde?
Ich habe ein Python-Programm (genau genommen eine Django-Anwendung), mit dem ein Unterprozess gestartet wirdsubprocess.Popen
. Aufgrund von Architekturbeschränkungen meiner Anwendung kann ich nicht verwendenPopen.terminate()
zum Beenden des Unterprozesses undPopen.poll()
um zu überprüfen, wann der Prozess beendet wurde. Dies liegt daran, dass ich keinen Verweis auf den gestarteten Unterprozess in einer Variablen halten kann.
Stattdessen muss ich die Prozess-ID schreibenpid
in eine Dateipidfile
wenn der Unterprozess startet. Wenn ich den Subprozess stoppen möchte, öffne ich diesenpidfile
und verwendenos.kill(pid, signal.SIGTERM)
um es zu stoppen.
Meine Frage ist: Wie kann ich herausfinden, wann der Teilprozess wirklich beendet wurde? Verwendensignal.SIGTERM
Es dauert ungefähr 1-2 Minuten, um nach dem Anruf endgültig zu beendenos.kill()
. Zuerst habe ich das gedachtos.waitpid()
wäre das richtige für diese aufgabe aber wenn ich es danach anrufeos.kill()
es gibt mirOSError: [Errno 10] No child processes
.
Übrigens starte und stoppe ich den Unterprozess einer HTML-Vorlage mit zwei Formularen und die Programmlogik befindet sich in einer Django-Ansicht. Die Ausnahme wird in meinem Browser angezeigt, wenn sich meine Anwendung im Debug-Modus befindet. Es ist wahrscheinlich auch wichtig zu wissen, dass der von mir aufgerufene Subprozess (python manage.py crawlwebpages
) selbst ruft einen anderen Unterprozess auf, nämlich eine Instanz eines Scrapy-Crawlers. Ich schreibe diepid
dieser Scrapy-Instanz an diepidfile
und das ist, was ich beenden möchte.
Hier ist der relevante Code:
def process_main_page_forms(request):
if request.method == 'POST':
if request.POST['form-type'] == u'webpage-crawler-form':
template_context = _crawl_webpage(request)
elif request.POST['form-type'] == u'stop-crawler-form':
template_context = _stop_crawler(request)
else:
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': StopCrawlerForm()}
return render(request, 'main.html', template_context)
def _crawl_webpage(request):
webpage_crawler_form = WebPageCrawlerForm(request.POST)
if webpage_crawler_form.is_valid():
url_to_crawl = webpage_crawler_form.cleaned_data['url_to_crawl']
maximum_pages_to_crawl = webpage_crawler_form.cleaned_data['maximum_pages_to_crawl']
program = 'python manage.py crawlwebpages' + ' -n ' + str(maximum_pages_to_crawl) + ' ' + url_to_crawl
p = subprocess.Popen(program.split())
template_context = {
'webpage_crawler_form': webpage_crawler_form,
'stop_crawler_form': StopCrawlerForm()}
return template_context
def _stop_crawler(request):
stop_crawler_form = StopCrawlerForm(request.POST)
if stop_crawler_form.is_valid():
with open('scrapy_crawler_process.pid', 'rb') as pidfile:
process_id = int(pidfile.read().strip())
print 'PROCESS ID:', process_id
os.kill(process_id, signal.SIGTERM)
os.waitpid(process_id, os.WNOHANG) # This gives me the OSError
print 'Crawler process terminated!'
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': stop_crawler_form}
return template_context
Was kann ich machen? Vielen Dank!
BEARBEITEN:
Gemäßdie gute antwort gegeben durchJacek KoniecznyIch könnte mein Problem lösen, indem ich meinen Code in der Funktion ändere_stop_crawler(request)
Zu dem Folgendem:
def _stop_crawler(request):
stop_crawler_form = StopCrawlerForm(request.POST)
if stop_crawler_form.is_valid():
with open('scrapy_crawler_process.pid', 'rb') as pidfile:
process_id = int(pidfile.read().strip())
# These are the essential lines
os.kill(process_id, signal.SIGTERM)
while True:
try:
time.sleep(10)
os.kill(process_id, 0)
except OSError:
break
print 'Crawler process terminated!'
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': stop_crawler_form}
return template_context