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)

InformationsquelleAutor pemistahl | 2012-11-15
Schreibe einen Kommentar