Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么可以';这个Python多处理过程不能从Kivy终止吗?_Python_Django_Multiprocessing_Kivy - Fatal编程技术网

为什么可以';这个Python多处理过程不能从Kivy终止吗?

为什么可以';这个Python多处理过程不能从Kivy终止吗?,python,django,multiprocessing,kivy,Python,Django,Multiprocessing,Kivy,我正在尝试从Kivy应用程序中运行django开发服务器。到目前为止,这确实很有效 现在我想允许用户在服务器运行时继续使用该程序。我的想法是为httpd.serve_forever()创建一个multiprocessing.Process,以避免主程序被完全锁定。我做得很好。这是我的内部_django模块中的代码: import multiprocessing import os import time from wsgiref.simple_server import make_server

我正在尝试从Kivy应用程序中运行django开发服务器。到目前为止,这确实很有效

现在我想允许用户在服务器运行时继续使用该程序。我的想法是为httpd.serve_forever()创建一个multiprocessing.Process,以避免主程序被完全锁定。我做得很好。这是我的内部_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()
但在这样做的时候,这个过程一旦开始就不会停止。我的第一个想法是Singleton没有像预期的那样工作,我试图退出错误的流程。但正如您在输出中看到的,PID是相同的。服务器接收到终止命令,但只是继续工作。这是控制台的外观:

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是否以某种方式干扰了该过程?

如果调用
terminate()
,然后调用
join()
并跳过while循环,会发生什么?另外,我对代码进行了一些洗牌,并将一些代码分解到
\u create\u 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")

我认为这里的问题可能有两个:

  • 信号处理程序正在拦截Process.terminate()发送的术语请求并将其忽略。要验证这一点,只需在新进程中使用signal.getsignal(signal.SIGTERM)并打印结果。为了避免这个问题,您可以使用signal.signal(signal.SIGTERM,signal.SIG_DFL)重置默认行为,但是请记住,SIGTERM被框架禁用可能有一个原因(我对Django和Kivy都不熟悉)

  • >P>如果您使用Python 2,则必须考虑解释器如果在同步基元上从线程库(锁、信号量……)或在本地C调用上被阻止,则不处理信号。在这些情况下,serve_forever()函数可能会失败(请使用源代码的强制!)。快速检查可以尝试在Python3上运行代码,看看它是否有效

    一个快速而肮脏的解决方案是等待一小段时间,并在进程仍处于活动状态时发送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的原因


    这是一种非常原始的方法,因此我建议找出问题的原因。

    多久启动/停止一次服务器?如果您只启动它一次,并在退出Kivy应用程序时停止,那么只需将服务器设置为守护进程,而不用担心停止它。在调用
    self.server.start()
    self.server.daemon=True
    之前执行此操作。在我看来,这将使服务器进程保持活动状态,这将导致在重新启动应用程序时阻塞连接端口(或尝试在相关端口上提供服务的任何其他本地服务)。不是我想要的。每次点击相应的按钮时,服务器应该通过用户交互来启动/停止。实际上,没有while循环的代码是我第一次尝试的,我只是引入了while循环作为一种快速破解,以确保我的问题不是由竞争条件引起的。我只是使用了您的代码,但问题仍然存在(只是在加入后主进程被锁定时,没有一直打印)。