热交换Python运行程序 [英] Hot-swapping of Python running program

查看:109
本文介绍了热交换Python运行程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码允许您在运行时修改runtime.py的内容.换句话说,您不必中断runner.py.

The following code allows you to modify the contents of runtime.py at run time. In other words, you don't have to interrupt 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()

在运行时导入的模块为:

The module imported at runtime is:

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

这种原始机制使您可以如何交换" Python代码(la Erlang).有更好的选择吗?

This primitive mechanism allows you to "how-swap" Python code (a la Erlang). Is there a better alternative?

请注意,这只是一个学术问题,因为我没有必要做这样的事情.但是,我有兴趣了解有关Python运行时的更多信息.

Please notice that this is a merely academic question, as I don't have the necessity to do anything like this. However, I am interested in learning more about the Python runtime.

修改:

我创建了以下解决方案:Engine对象提供了模块中包含的功能的接口(在这种情况下,该模块称为engine.py). Engine对象还产生一个线程,该线程监视源文件中的更改,并且如果检测到更改,它将调用引擎上的notify()方法,该方法将重新加载源文件.

I created the following solution: an Engine object provides an interface to the functions contained in a module (in this case the module is called engine.py). The Engine object also spawns a thread which monitors for changes in the source file and, if changes are detected, it calls the notify() method on the engine, which reloads the source file.

在我的实现中,更改检测基于每frequency秒轮询一次,以检查文件的SHA1校验和,但是其他实现也是可能的.

In my implementation, the change detection is based on polling every frequency seconds checking the SHA1 checksum of the file, but other implementations are possible.

在此示例中,每个检测到的更改都记录到名为hotswap.log的文件中,并在其中注册了校验和.

In this example every change detected is logged to a file called hotswap.log, where the checksum is registered.

用于检测更改的其他机制可以是服务器,也可以在Monitor线程中使用inotify.

Other mechanisms for detecting changes could be a server or the use of inotify in the Monitor thread.

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)

再次-这是一个学术讨论,因为我现在不需要热交换Python代码.但是,我喜欢能够稍微了解运行时并认识到可能的事和不可能的事.请注意,如果加载机制正在使用资源,则加载机制可以添加一个锁;如果模块加载失败,则可以添加异常处理.

Again - this is an academic discussion because I have no need at this moment of hot-swapping Python code. However, I like being able to understand a little bit the runtime and realize what is possible and what is not. Notice that the loading mechanism could add a lock, in case it is using resources, and exception handling, in case the module is not loaded successfully.

评论?

推荐答案

您可以轮询runtime.py文件,等待其更改.更改后,只需致电

You could poll the runtime.py file, waiting for it to change. Once it changes, just call

reload(runtime)

每当我调试python模块时,我都会在交互式python命令提示符中使用这种方法(除了我手动调用reload()之外,我不会轮询任何东西).

Any time I'm debugging a python module, I use this approach in the interactive python command prompt (except I manually call reload(), I don't poll anything).

要检测文件中的更改,请查看此SO问题.轮询可能是最可靠的选择,但是我只会在修改时间更新后才重新加载文件,而不是在每次轮询时都重新加载文件.您还应该考虑在重新加载时捕获异常,尤其是语法错误.而且您可能会也可能不会遇到线程安全性问题.

To detect changes in a file, check out this SO question. Polling may be the most reliable option, but I would only reload the file if the modified time is updated, rather than reloading it on every poll. You should also consider catching exceptions when you reload, especially syntax errors. And you may or may not encounter problems with thread safety.

这篇关于热交换Python运行程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆