Wie finden Sie heraus, wenn der Unterprozess beendet hat, nach der Verwendung von os.kill()?
Habe ich ein Python-Programm (genau, eine Django-Anwendung), startet einen Teilprozess mit Unterprozess.Popen
. Aufgrund der Architektur Einschränkungen meiner Bewerbung, ich bin nicht in der Lage zu verwenden Popen.terminate()
zu kündigen, Teilprozess und Popen.poll()
zu prüfen, Wann der Prozess beendet wurde. Das ist, weil ich Sie nicht halten eine Referenz auf den gestarteten Unterprozess in einer Variablen.
Statt, ich habe das schreiben der Prozess-id pid
zu einer Datei pidfile
wenn der Teilprozess beginnt. Wenn ich aufhören will zu den Teilprozess, ich öffne das pidfile
und verwenden os.kill(pid, signal.SIGTERM)
, um es zu stoppen.
Meine Frage ist: Wie kann ich herausfinden, wenn der Unterprozess hat wirklich beendet? Mit signal.SIGTERM
es braucht etwa 1-2 Minuten, um endlich beenden Sie nach dem Aufruf os.kill()
. Zuerst dachte ich, dass os.waitpid()
wäre der richtige für diese Aufgabe, aber wenn ich es nach os.kill()
es gibt mir OSError: [Errno 10] No child processes
.
Durch die Art und Weise, ich bin das starten und stoppen der Teilprozess aus einer HTML-Vorlage mit zwei Formen und die Programm-Logik wird innerhalb einer Django-Ansicht. Die Ausnahme erscheint in meinem browser, wenn meine Anwendung im debug-Modus. Es ist wohl auch wichtig zu wissen, dass der Teilprozess, dass ich in meiner Ansicht (python manage.py crawlwebpages
) selbst ruft ein weiterer Teilprozess, nämlich eine Instanz einer Scrapy-crawler. Ich Schreibe die pid
dieser Scrapy-Instanz der pidfile
und das ist, was ich will, zu beenden.
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 tun? Ich danke Ihnen sehr!
EDIT:
Laut die große Antwort gegeben durch Jacek Konieczny, ich konnte mein problem lösen, indem Sie meinen code in der Funktion _stop_crawler(request)
um die folgenden:
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
- Versucht haben Sie es vor? Vielleicht ist diese Ausnahme bedeutet, dass die angegebenen Teilprozess gibt es nicht mehr...
- Ja, ich habe es versucht. Wenn diese Ausnahme ist aufgetreten der jeweilige Prozess noch aktiv war nach dem activity monitor (ich verwende Mac OSX als mein Betriebssystem.) 1-2 Minuten später ist es endlich beendet.
- Sie können nicht verwenden, waitpid, weil ein Prozess zu sein, der Muttergesellschaft von diesem Prozess. Wenn er gezwungen ist, Sie zu verwenden pidfiles er wohl waitpid-Aufrufe von einem anderen Prozess als Popen.
- Richtig, das fiel mir nach dem schreiben mein Kommentar. So entstand die Idee, eine intermediate-Prozess.
- Wie Sie sehen können in meinem code Hinzugefügt, ich nenne
os.waitpid()
aus der gleichen Ansicht und deshalb sollte es der gleiche Prozess und nicht ein anderes. Oder ich missverstehen Sie? - Sie können nicht sicher sein, beim ausführen von python web-Anwendungen, zumindest durch WSGI, die kann leicht laichen mehrere Prozesse, um Anfragen zu bedienen. Sie können sicher sein, dass es der gleiche Prozess. Vielleicht könnten Sie schreiben
os.pid()
in der PID und vergleichen? - wenn Sie einen separaten Prozess, sagen viele Raupen. Prozess.isAlive() gibt auch den trick tun, solange Sie speichern Ihre Prozesse in ein array. (just in case)
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den üblichen Weg, um zu überprüfen, ob ein Prozess noch ausgeführt wird, ist zu töten() mit signal '0'. Es tut nichts, um einen Laufenden job und wirft einen
OSError
Ausnahme miterrno=ESRCH
wenn der Prozess nicht vorhanden ist.Aber Wann immer möglich, die Anrufer bleiben sollte ein Elternteil der genannten Verarbeitung und Nutzung
wait()
Funktion der Familie für die Kündigung. Das ist das, wasPopen
Objekt macht.OSError: [Errno 3] No such process
in der Konsole, aber das ist ein kleineres Problem.os.kill(process_id, signal.SIGTERM)
in einem anderentry ... except
beheben dieses Thema?Meine Lösung wäre ein intermediate-Prozess, die Kontrollen Vergabe eines unterauftrags.
Damit Ihr web-Anfragen (die scheinen alle zu geschehen, die in verschiedenen Prozessen - durch Parallelisierung?) sagen Sie dem control-Prozess zu starten ein bestimmtes Programm und beobachten Sie es; sobald Sie benötigt zu Fragen, was der status ist.
Dieser Prozess würde im einfachsten Fall ein Prozess, der öffnet einen UNIX-domain-socket (TCP/IP-socket nicht genauso gut wäre) und hören Sie es. Die "web-Prozess" mit ihm verbindet, sendet die Anfrage starten und erhält eine eindeutige ID. Danach kann er diese ID verwenden, um weitere Abfragen auf den neuen Prozess.
Alternativ, gibt es die ID von selbst (oder er verwendet nicht die ID, wenn es nur ein Prozess) und so nicht zu halten einige Variablen-ID um.
os.waitpid()
gibt mir die Fehlermeldung, wie oben gezeigt, richtig? Nach meinem code von oben, wie würden Sie hinzufügen, um dieses Steuerelement zu verarbeiten? Ich bin noch ein Anfänger, wenn es um die Teilprozesse und Parallelisierung. Danke!!!