2014-11-16 7 views
5

मैं एक किवी अनुप्रयोग के भीतर से एक django विकास सर्वर चलाने की कोशिश कर रहा हूँ। यह अब तक काफी अच्छा काम किया है।यह पाइथन मल्टीप्रोसेसिंग प्रक्रिया कोवी से क्यों समाप्त नहीं किया जा सकता है?

अब मैं उपयोगकर्ता को चल रहा है, जबकि प्रोग्राम प्रोग्राम के साथ काम करना जारी रखने की अनुमति देना चाहता हूं। मेरा विचार मुख्य प्रोग्राम के पूर्ण लॉक से बचने के लिए httpd.serve_forever() के लिए एक multiprocessing.Process बनाना था। अच्छा काम किया था।

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() 

जब मैं इस कोड को चलाने के लिए, सब कुछ उम्मीद के रूप में काम करता है: यह मेरा internal_django मॉड्यूल में कोड है। यह वही है कंसोल में बाहर कर दिया जा रहा है:

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 आवेदन के भीतर से सर्वर बंद करने के लिए एक तरह से प्रदान करना था।

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() 

लेकिन जब ऐसा करने से, इस प्रक्रिया को एक बार शुरू कभी नहीं इस्तीफा: उस के लिए मैं बस के रूप में मैंने किया इससे पहले कि मेरे DjangoServer वर्ग उपयोग करना चाहता था। मेरा पहला विचार यह था कि सिंगलटन अपेक्षित काम नहीं करता था, और मैं गलत प्रक्रिया को छोड़ने की कोशिश करता हूं। लेकिन जैसा कि आप आउटपुट में देख सकते हैं, पीआईडी ​​समान हैं। सर्वर को समाप्त आदेश प्राप्त होता है, लेकिन अभी भी काम करना जारी रखता है। यह कंसोल जैसा दिखता है:

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 किसी भी तरह से प्रक्रिया में हस्तक्षेप कर रहा है?

+0

सर्वर को कितनी बार शुरू/बंद करना है? यदि आप इसे केवल एक बार शुरू करते हैं, और Kivy एप्लिकेशन से बाहर निकलने पर रोकें, तो बस सर्वर को एक डिमन बनाएं और इसे रोकने के बारे में चिंता न करें। 'Self.server.start() ':' self.server.daemon = True' –

+0

पर कॉल करने से पहले ऐसा करें, जहां तक ​​मैं इसे देखता हूं यह सर्वर प्रक्रिया को जीवित रखेगा, जिससे एप्लिकेशन को पुनरारंभ करते समय अवरुद्ध कनेक्शन पोर्ट हो जाएगा (या किसी भी अन्य स्थानीय सेवा में बंदरगाह पर सेवा करने की कोशिश कर रहे हैं)। मैं क्या चाहता हूँ नहीं। प्रत्येक बार दिए गए बटन पर क्लिक होने पर सर्वर को उपयोगकर्ता इंटरैक्शन के माध्यम से प्रारंभ/बंद करना चाहिए। – marue

उत्तर

1

क्या होता है यदि आप terminate() पर कॉल करते हैं, तो join() और जबकि लूप को छोड़ दें? इसके अलावा, मैं कोड को थोड़ा सा घुमाता हूं और कुछ कोड _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") 
+0

असल में लूप के बिना कोड मेरी पहली कोशिश थी, मैंने बस थोड़ी देर के रूप में लूप को एक त्वरित हैक के रूप में पेश किया ताकि यह सुनिश्चित किया जा सके कि मेरी परेशानी दौड़ की स्थिति के कारण नहीं थी। मैंने बस आपके कोड का उपयोग किया था, लेकिन समस्या बनी हुई है (केवल शामिल होने के बाद मुख्य प्रक्रिया लॉक हो जाने पर ही प्रिंट करने की बजाय)। – marue

3

मुझे लगता है कि यहां की समस्याओं दो हो सकता है:

  1. एक संकेत हैंडलर Process.terminate द्वारा भेजे गए सावधि अनुरोध() में अवरोध डालने और यह ध्यान नहीं देता है। यह सत्यापित करने के लिए कि केवल नई प्रक्रिया के भीतर सिग्नल.getsignal (सिग्नल.SIGTERM) का उपयोग करें और परिणामों को प्रिंट करें। इस तरह की समस्या को रोकने के लिए आप सिग्नल.signal (सिग्नल.SIGTERM, सिग्नल.SIG_DFL) के साथ डिफ़ॉल्ट व्यवहार को रीसेट कर सकते हैं, फिर भी ध्यान रखें कि SIGTERM को ढांचे से चुप क्यों किया जा सकता है (मैं Django के साथ परिचित नहीं हूं न ही किवी के साथ)।

  2. यदि आप पाइथन 2 का उपयोग कर रहे हैं तो आपको यह समझना चाहिए कि अगर दुभाषिया थ्रेडिंग लाइब्रेरी (ताले, सेमफोरस ..) या मूल सी कॉल पर सिंक्रनाइज़ेशन पर सिंक्रनाइज़ेशन पर अवरुद्ध है तो दुभाषिया संकेतों को संसाधित नहीं करता है। Serv_forever() फ़ंक्शन इन मामलों में पड़ सकता है (स्रोत की शक्ति का उपयोग करें!)। त्वरित जांच पाइथन 3 पर कोड चलाने की कोशिश कर रही है और देख सकती है कि यह काम करता है या नहीं।

एक त्वरित और गंदे समाधान में थोड़ी सी प्रतीक्षा की प्रतीक्षा होती है और यदि प्रक्रिया अभी भी जिंदा है तो सिगकिल भेजती है।

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 

खिड़कियों पर आप है यही कारण है कि मैं os.name का परीक्षण इस तरह के सरल तरीके से एक प्रक्रिया को नहीं मार सकते हैं।

यह एक बहुत ही कच्चा दृष्टिकोण है इसलिए मैं इस मुद्दे का कारण खोजने की सिफारिश करता हूं।

संबंधित मुद्दे

 संबंधित मुद्दे