Python中的反应事件循环

时间:2014-11-18 22:37:48

标签: python events publish-subscribe multiprocess reactor

我正在尝试使用I / O(HDD,网络......)构建一个从某些来源收集数据的系统

为此,我有一个启动收集器的类(控制器)。

每个收集器都是一个带有经典ETL过程(提取,转换和加载)的无限循环。

我想从界面(CLI,web ...)向收集器发送一些命令(停止,重新加载设置...),我不知道该怎么做。

例如,这是收集器的骨架:

class Collector(object):
    def __init__(self):
        self.reload_settings()

    def reload_settings(self):
        # Get the settings
        # Set the settings as attributes

    def process_data(self, data):
        # Do something

    def run(self):
        while True:
            data = retrieve_data()
            self.process_data(data)

这是控制器的骨架:

class Controller(object):
    def __init__(self, collectors):
        self.collectors = collectors

    def run(self):
        for collector in collectors:
            collector.run()

    def reload_settings(self):
        ??

    def stop(self):
        ??

是否有解决此问题的经典设计模式(Publish-subscribe,event loop,reactor ...)?解决这个问题的最佳方法是什么?

PD:显然,这将是一个多进程应用程序,将在一台机器上运行。

2 个答案:

答案 0 :(得分:1)

这里有多种选择,但它们归结为两种主要类型:协作(事件循环/反应器/协程/显式greenlet)或抢占(隐式greenlet /线程/多进程)。

首先需要对收藏家进行更多重组。它可以是一种很好的方法来使非确定性显式,或实现大规模并发,但这些似乎都不相关。第二个只需要将收集器粘贴在线程上,并使用一些同步机制来进行通信和共享数据。您似乎没有共享数据,并且您的通信很简单,而且对时间不敏感。所以,我选择了线程。

假设您想要使用一般意义上的线程,假设您的收集器受I / O限制并且您没有数十个,我会选择实际的线程。

所以,这是你可以写的一种方式:

class Collector(threading.Thread):
    def __init__(self):
        self._reload_settings()
        self._need_reload = threading.Event()
        self._need_stop = threading.Event()

    def _reload_settings(self):
        # Get the settings
        # Set the settings as attributes
        self._need_reload.clear()

    def reload_settings(self):
        self._need_reload.set()

    def stop(self):
        self._need_stop.set()

    def process_data(self, data):
        # Do something

    def run(self):
        while not self._need_stop.is_set():
            if self._need_reload.is_set():
                self._reload_settings()
            data = retrieve_data()
            self.process_data(data)

class Controller(object):
    def __init__(self, collectors):
        self.collectors = collectors

    def run(self):
        for collector in self.collectors:
            collector.start()

    def reload_settings(self):
        for collector in self.collectors:
            collector.reload_settings()

    def stop(self):
        for collector in self.collectors:
            collector.stop()
        for collector in self.collectors:
            collector.join()

(虽然我会调用Controller.run方法stop,因为它不仅适用于Thread使用的命名,而且适用于stdlib服务器类和其他类似的事情。)

答案 1 :(得分:0)

我会考虑将您的案例调整为基于套接字的客户端 - 服务器架构的可能性,其中Controller将实例化所需数量的收集器,每个收集器都在其自己的端口上侦听,并通过handle()方法以更优雅的方式处理接收到的数据服务器。数据来自各种I / O源的事实对此解决方案说得更多 - 您可以使用此体系结构的客户端部分来标准化DataSource - >收集器协议

https://docs.python.org/2/library/socketserver.html