2011-07-19 16 views
18

निम्न कोड आपको रन समय पर runtime.py की सामग्री को संशोधित करने की अनुमति देता है। दूसरे शब्दों में, आपको runner.py को बाधित करने की आवश्यकता नहीं है।पायथन रनिंग प्रोग्राम का हॉट-स्वैपिंग

#runner.py 
import time 
import imp 

def main(): 
    while True: 
     mod = imp.load_source("runtime", "./runtime.py") 
     mod.function() 
     time.sleep(1) 

if __name__ == "__main__": 
    main() 

मॉड्यूल कार्यावधि में आयातित है:

# runtime.py 
def function(): 
    print("I am version one of runtime.py") 

यह आदिम तंत्र की अनुमति देता है आप के लिए "कैसे-स्वैप" अजगर कोड (एक ला Erlang)। क्या कोई बेहतर विकल्प है?

कृपया ध्यान दें कि यह एकमात्र अकादमिक प्रश्न है, क्योंकि मुझे ऐसा कुछ करने की आवश्यकता नहीं है। हालांकि, मुझे पाइथन रनटाइम के बारे में अधिक जानने में दिलचस्पी है।

संपादित:

मैं निम्नलिखित समाधान बनाया: एक Engine वस्तु (इस मामले मॉड्यूल engine.py कहा जाता है) में एक मॉड्यूल में निहित कार्यों के लिए एक इंटरफेस प्रदान करता है। Engine ऑब्जेक्ट भी थ्रेड उत्पन्न करता है जो स्रोत फ़ाइल में परिवर्तनों की निगरानी करता है और यदि परिवर्तनों का पता चला है, तो यह इंजन पर notify() विधि को कॉल करता है, जो स्रोत फ़ाइल को पुनः लोड करता है।

मेरे कार्यान्वयन में, परिवर्तन पहचान फ़ाइल के SHA1 चेकसम की जांच करने वाले प्रत्येक frequency सेकंड पर मतदान पर आधारित है, लेकिन अन्य कार्यान्वयन संभव है।

इस उदाहरण में hotswap.log नामक फ़ाइल में प्रत्येक परिवर्तन का पता चला है, जहां चेकसम पंजीकृत है।

परिवर्तनों का पता लगाने के लिए अन्य तंत्र Monitor धागे में एक सर्वर या inotify का उपयोग हो सकता है।

import imp 
import time 
import hashlib 
import threading 
import logging 

logger = logging.getLogger("") 

class MonitorThread(threading.Thread): 
    def __init__(self, engine, frequency=1): 
     super(MonitorThread, self).__init__() 
     self.engine = engine 
     self.frequency = frequency 
     # daemonize the thread so that it ends with the master program 
     self.daemon = True 

    def run(self): 
     while True: 
      with open(self.engine.source, "rb") as fp: 
       fingerprint = hashlib.sha1(fp.read()).hexdigest() 
      if not fingerprint == self.engine.fingerprint: 
       self.engine.notify(fingerprint) 
      time.sleep(self.frequency) 

class Engine(object): 
    def __init__(self, source): 
     # store the path to the engine source 
     self.source = source   
     # load the module for the first time and create a fingerprint 
     # for the file 
     self.mod = imp.load_source("source", self.source) 
     with open(self.source, "rb") as fp: 
      self.fingerprint = hashlib.sha1(fp.read()).hexdigest() 
     # turn on monitoring thread 
     monitor = MonitorThread(self) 
     monitor.start() 

    def notify(self, fingerprint): 
     logger.info("received notification of fingerprint change ({0})".\ 
         format(fingerprint)) 
     self.fingerprint = fingerprint 
     self.mod = imp.load_source("source", self.source) 

    def __getattr__(self, attr): 
     return getattr(self.mod, attr) 

def main(): 
    logging.basicConfig(level=logging.INFO, 
         filename="hotswap.log") 
    engine = Engine("engine.py") 
    # this silly loop is a sample of how the program can be running in 
    # one thread and the monitoring is performed in another. 
    while True: 
     engine.f1() 
     engine.f2() 
     time.sleep(1) 

if __name__ == "__main__": 
    main() 

engine.py फ़ाइल:

# this is "engine.py" 
def f1(): 
    print("call to f1") 

def f2(): 
    print("call to f2") 

लॉग नमूना:

INFO:root:received notification of fingerprint change (be1c56097992e2a414e94c98cd6a88d162c96956) 
INFO:root:received notification of fingerprint change (dcb434869aa94897529d365803bf2b48be665897) 
INFO:root:received notification of fingerprint change (36a0a4b20ee9ca6901842a30aab5eb52796649bd) 
INFO:root:received notification of fingerprint change (2e96b05bbb8dbe8716c4dd37b74e9f58c6a925f2) 
INFO:root:received notification of fingerprint change (baac96c2d37f169536c8c20fe5935c197425ed40) 
INFO:root:received notification of fingerprint change (be1c56097992e2a414e94c98cd6a88d162c96956) 
INFO:root:received notification of fingerprint change (dcb434869aa94897529d365803bf2b48be665897) 

फिर से - यह एक शैक्षिक चर्चा क्योंकि मैं गर्म गमागमन अजगर के इस समय कोई आवश्यकता नहीं है कोड। हालांकि, मुझे रनटाइम थोड़ा सा समझने में सक्षम होना पसंद है और यह पता है कि क्या संभव है और क्या नहीं है। ध्यान दें कि मॉड्यूल सफलतापूर्वक लोड नहीं होने पर लोडिंग तंत्र लॉक जोड़ सकता है, अगर यह संसाधनों का उपयोग कर रहा है, और अपवाद हैंडलिंग।

टिप्पणियां?

+1

अपने quesiton में एक उत्तर संपादित न करें। इसे एक उत्तर के रूप में जोड़ें। – agf

+1

संभावित डुप्लिकेट [मैं एक पायथन मॉड्यूल को अनलोड (पुनः लोड) कैसे करूं?] (Http://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module) –

उत्तर

1
globe = __import__('copy').copy(globals()) 
while True: 
    with open('runtime.py', 'r') as mod: 
     exec mod in globe 
    __import__('time').sleep(1) 

बार-बार पढ़ा होगा और एक लगभग प्रदूषणरहित globals() और कोई locals() साथ runtime.py चलाने के लिए, और वैश्विक क्षेत्र को प्रदूषित नहीं होगा, लेकिन क्रम के नाम स्थान के सभी globe

+1

यह दिलचस्प है , लेकिन क्या मैं नेमस्पेसिंग को खो नहीं सकता? – Escualo

+2

हां, आप करेंगे। मैंने माना कि 'runner.py' बार-बार पुनः लोड करने और' runtime.py' से कोड को फिर से निष्पादित करने के लिए एक सहायक है, इसलिए आपको परवाह नहीं है। आपको इसके बजाय 'ग्लोबल्स()' की प्रतिलिपि बनाना होगा, इसे दिखाने के लिए संपादन करना होगा। – agf

7

आप क्रम मतदान कर सकता है में उपलब्ध हो जाएगा .py फ़ाइल, इसे बदलने के लिए इंतजार कर रहा है।एक बार जब यह बदलता है, सिर्फ फोन

reload(runtime) 

किसी भी समय मैं एक अजगर मॉड्यूल डिबगिंग कर रहा हूँ, मैं() को छोड़कर मैं मैन्युअल रूप से (पुनः लोड कहते हैं, मैं कुछ भी मतदान नहीं करते हैं) इंटरैक्टिव अजगर कमांड प्रॉम्प्ट में इस दृष्टिकोण का उपयोग करें।

संपादित करें: फ़ाइल में परिवर्तनों का पता लगाने के लिए, this SO question देखें। मतदान सबसे विश्वसनीय विकल्प हो सकता है, लेकिन अगर मैं संशोधित समय अद्यतन करता हूं, तो प्रत्येक मतदान पर इसे पुनः लोड करने के बजाय, मैं केवल फ़ाइल को फिर से लोड कर दूंगा। जब आप पुनः लोड करते हैं, विशेष रूप से सिंटैक्स त्रुटियों को अपवादों को पकड़ने पर भी विचार करना चाहिए। और आप थ्रेड सुरक्षा के साथ समस्याओं का सामना कर सकते हैं या नहीं।

+1

वास्तव में, फ़ंक्शन रीलोड और imp.load_source समकक्ष हैं। मुझे लगता है कि मैं "मतदान" या "श्रोता" तंत्र में अधिक रूचि रखता हूं जो दलालों को पुनः लोड करने की व्यवस्था करता है। धन्यवाद! – Escualo

0

आप गर्म स्वैप कोड है कि जब आप कार्यों आदि से बाहर आयात का उपयोग के रूप में पाया चाहते हैं, मॉड्यूल की एक वैश्विक वर के ऊपर लिख आप की जरूरत है, अगर उदाहरण के लिए आप का उपयोग करें:

import mylib 

आप जब लोड मॉड्यूल की जरूरत है नया मॉड्यूल mylib करने के लिए कोड asign में। अन्य क्यूशन इस प्रोग्राम में आज़माते हैं जो धागे के साथ सुरक्षित है, और थ्रेड के साथ सुरक्षित है, जब मल्टीप्रोसेसिंग का उपयोग केवल एक प्रक्रिया में पाया जाता है, सभी प्रक्रियाओं में परिवर्तन कोड के लिए सभी को नए कोड लोड करने की आवश्यकता होती है, मल्टीप्रोसेस में सुरक्षित होने पर निरंतर प्रयास किया जाता है।

और, यदि नया कोड है या एक ही कोड लोड नहीं करने के लिए पहले जांच कर रहा है तो पहले जांच कर रहा है। और पाइथन में सोचें केवल आप एक नया मॉड्यूल लोड कर सकते हैं और मॉड्यूल के परिवर्तनीय नाम को प्रतिस्थापित कर सकते हैं, लेकिन यदि आपको वास्तव में एक अच्छा गर्म परिवर्तन कोड चाहिए तो एरलांग भाषा और ओटीपी देखें, यह बहुत अच्छा है।

+1

इरलांग/ओटीपी का उपयोग करने का सुझाव मुझे लगता है कि कोड अच्छा, गलती-सहनशील सॉफ्टवेयर, और समवर्ती या निष्पादन वितरित करने के लिए हॉट-स्वैप की आवश्यकता होने पर सबसे अच्छा समाधान है। व्हाट्सएप एर्लांग में सर्वर चलाता है, फेसबुक चैट के लिए फेसबुक, तुएंटी भी, ड्यूटी सर्वर का कॉल इत्यादि। –

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