簡體   English   中英

為什么不能從Kivy終止這個Python多處理過程?

[英]Why can't this Python multiprocessing process be terminated from Kivy?

我正在嘗試從Kivy應用程序中運行django開發服務器。 到目前為止,這確實很順利。

現在我想讓用戶在服務器運行時繼續使用該程序。 我的想法是為httpd.serve_forever()創建一個multiprocessing.Process,以避免完全鎖定主程序。 工作得很好 這是我的internal_django模塊中的代碼:

import multiprocessing
import os
import time

from wsgiref.simple_server import make_server

def django_wsgi_application():

    PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
    settings_module = "djangosettings"#%s.djangosettings" % PROJECT_ROOT.split(os.sep)[-1]

    os.environ.update({"DJANGO_SETTINGS_MODULE":settings_module})

    from django.core.wsgi import get_wsgi_application
    application = get_wsgi_application()

    return application


class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class DjangoServer():
    __metaclass__ = Singleton

    def start(self):
        self.httpd = make_server('', 8000, django_wsgi_application())
        self.server = multiprocessing.Process(target=self.httpd.serve_forever)
        self.server.start()
        print "Now serving on port 8000..."
        print "Server Process PID = %s" %self.server.pid

    def stop(self):
        print("shutdown initiated")
        print "Server Process PID = %s" %self.server.pid
        while self.server.is_alive():
            self.server.terminate()
            print("Server should have shut down")
            time.sleep(1)
        print("Server is_alive: %s" %self.server.is_alive())
        self.server.join()
        print("server process joined")



if __name__ == "__main__":
    server = DjangoServer()
    server.start()
    time.sleep(3)
    server.stop()

當我運行此代碼時,一切都按預期工作。 這是在控制台中發布的內容:

Now serving on port 8000...
Server Process PID = 1406
shutdown initiated
Server Process PID = 1406
Server should have shut down
Server is_alive: False
server process joined

下一步是提供一種從Kivy應用程序中停止服務器的方法。 為此,我只想像以前一樣使用我的DjangoServer類:

from internal_django import DjangoServer

class StartScreen(Screen): 
    def start_server(self):
        server = DjangoServer()
        server.start()


class StopScreen(Screen):  
    def stop_server(self):
        server = DjangoServer()
        server.stop()

但是這樣做的過程一旦開始就永遠不會退出。 我的第一個想法是,單身人士沒有按預期工作,我試圖退出錯誤的過程。 但正如您在輸出中看到的那樣,PID是相同的。 服務器接收terminate命令,但只是繼續工作。 這就是控制台的樣子:

Now serving on port 8000...
Server Process PID = 1406
shutdown initiated
Server Process PID = 1406
Server should have shut down
Server should have shut down
Server should have shut down
Server should have shut down
Server should have shut down
Server should have shut down
Server should have shut down
Server should have shut down

(and so on, until i manually kill the server process)

我是以完全錯誤的方式使用多處理嗎? Kivy是否以某種方式干擾了這個過程?

我認為這里的問題可能是兩個:

  1. 信號處理程序正在攔截Process.terminate()發送的TERM請求並忽略它。 要驗證是否只是在新進程中使用signal.getsignal(signal.SIGTERM)並打印結果。 為避免此類問題,您可以使用signal.signal(signal.SIGTERM,signal.SIG_DFL)重置默認行為,但請記住,可能有一個原因導致SIGTERM被框架靜音(我對Django不熟悉)也不是Kivy)。

  2. 如果您正在使用Python 2,則必須考慮解釋器在處理來自線程庫(Locks,Semaphores ...)或本機C調用的同步原語時不處理信號。 在這些情況下,serve_forever()函數可能會掉落(使用源的力!)。 快速檢查可能是嘗試在Python 3上運行代碼並查看它是否有效。

快速而骯臟的解決方案包括等待少量時間並在進程仍然存在時發送SIGKILL。

import os
import signal

process.terminate()
process.join(1)

if process.is_alive() and os.name != 'nt':
    try:
        os.kill(process.pid, signal.SIGKILL)
        process.join()
    except OSError:
        return  # process might have died while checking it

在Windows上,你不能以如此簡單的方式殺死進程,這就是我測試os.name的原因。

這是一個非常原始的方法,所以我寧願建議找到問題的原因。

如果你調用terminate() ,然后join()並跳過while循環會發生什么? 此外,我稍微調整了代碼並將一些代碼放入_create_server() 如果這對您有用,請告訴我。

class DjangoServer():
    __metaclass__ = Singleton

    def _create_server(self):
        httpd = make_server('', 8000, django_wsgi_application())
        print "Now serving on port {}...".format(httpd.server_port)
        httpd.serve_forever()

    def start(self):
        self.server = multiprocessing.Process(target=self._create_server)
        self.server.start()
        print "Server Process PID = %s" %self.server.pid

    def stop(self):
        print("shutdown initiated")
        print "Server Process PID = %s" %self.server.pid
        self.server.terminate()
        self.server.join()
        print("server process terminated")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM