将队列传递给python中的看门狗线程

时间:2019-03-06 15:14:28

标签: python multithreading queue watchdog

我有一个从主线程实例化的类Indexer,该类的实例存储在变量indexer中。 watchdog.observers.Observer()监视目录中的更改,这些更改发生在另一个线程中。我尝试通过主处理程序indexer从主线程传递此Vigilante变量,该处理程序与主线程的其他一些变量一起传递给ob.schedule(Vigilante(indexer))。由于处于不同的线程中,因此无法访问indexer中的Vigilante class变量。我知道我可以使用Queue,但不知道如何将Queue传递给看门狗的线程。

以下是主线程中的代码:

if watch:
    import watchdog.observers
    from .utils import vigilante
    class callbacks:
        def __init__(self):
            pass
        @staticmethod
        def build(filename, response):
            return _build(filename, response)
        @staticmethod
        def renderer(src, mode):
            return render(src, mode)
    handler = vigilante.Vigilante(_filter, ignore, Indexer, callbacks, Mode)
    path_to_watch = os.path.normpath(os.path.join(workspace, '..'))
    ob = watchdog.observers.Observer()
    ob.schedule(handler, path=path_to_watch, recursive=True)
    ob.start()
    import time
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        ob.stop()
        Indexer.close()
    ob.join()

Indexer class旨在从实例化Indexer的代码的另一部分写入数据库。

这是在监视程序的线程中运行的Vigilante类的代码:

class Vigilante(PatternMatchingEventHandler):
    """Helps to watch files, directories for changes"""
    def __init__(self, pattern, ignore, indexer, callback, mode):
        pattern.append("*.yml")
        self.Callback = callback
        self.Mode = mode
        self.Indexer = indexer
        super(Vigilante, self).__init__(patterns=pattern, ignore_directories=ignore)

    def vigil(self, event):
        print(event.src_path, 'modified')
        IndexReader = self.Indexer.get_index_on(event.src_path)
        dep = IndexReader.read_index()
        print(dep.next(), 'dependency')
        feedout = self.Callback.build(
            os.path.basename(event.src_path)
            ,self.Callback.renderer(event.src_path, self.Mode.FILE_MODE)
        )

    def on_modified(self, event):
        self.vigil(event)

    def on_created(self, event):
        self.vigil(event)

我需要的是一种通过Vigilante类将这些变量从主线程传递到看门狗线程的方法

2 个答案:

答案 0 :(得分:0)

您可以尝试使用Observer pattern(无双关语),即让Observer类有一个侦听器列表,它将通知您所看到的任何更改。然后让索引器向观察员宣布其兴趣。

在我的示例中,观察者期望订阅者是可接收更改的可调用对象。然后,您可以执行以下操作:

from queue import Queue
class Observable:
    def __init__(self):
        self.listeners = []
    def subscribe(listener):
        self.listeners.append(listener)
    def onNotify(change):
        for listener in self.listeners:
            listener(change)

class Indexer(Thread):
    def __init__(self, observer):
        Thread.__init__(self)
        self.q = Queue()
        observer.subscribe(self.q.put)
    def run(self):
        while True:
            change = self.q.get()

由于标准Queue完全是线程安全的,因此可以正常工作。

答案 1 :(得分:0)

我终于找到了一种方法,它不会像以前那样过多地交叉线程,其思想来自@EvertW的答案。我从主线程传递了一个Queue到另一个线程中的Vigilante类,因此每个修改后的文件都将被放在Queue中,然后从主线程得到从队列中修改的文件,从Indexer数据库中读取的文件以及Vigilante.vigil方法需要执行的所有其他任务都移到了主线程,因为这些任务取决于修改后的文件以及从Indexer数据库中读取的内容。

此错误消失了:

  

在线程中创建的SQLite对象只能在同一线程中使用。该对象在线程ID 9788中创建,该线程ID为4288。

这是我所做的摘录:

....
q = Queue.LifoQueue(10)
handler = vigilante.Vigilante(q, _filter, ignore)
path_to_watch = os.path.normpath(os.path.join(workspace, '..'))
ob = watchdog.observers.Observer()
ob.schedule(handler, path=path_to_watch, recursive=True)
ob.start()
import time
try:
    while True:
        if not q.empty():
            modified = q.get()
            IndexReader = Indexer.get_index_on(modified)
            deps = IndexReader.read_index()
            print(deps.next(), 'dependency')
            # TODO
        else:
            print('q is empty')
            time.sleep(1)
except KeyboardInterrupt:
    ob.stop()
    Indexer.close()
ob.join()

警戒类:

class Vigilante(PatternMatchingEventHandler):
    """Helps to watch files, directories for changes"""
    def __init__(self, q, pattern, ignore):
        self.q = q
        super(Vigilante, self).__init__(
            patterns=pattern, 
            ignore_patterns=ignore, 
            ignore_directories=True
        )

    def vigil(self, event):
        print(event.src_path, 'modified')
        self.q.put(event.src_path)

    def on_modified(self, event):
        self.vigil(event)

    def on_created(self, event):
        self.vigil(event)
....

PS:一个忠告:对任何遇到这种看门狗线程问题的人,我的忠告是: “不信任看门狗的线程在修改后的文件上执行任务,只是将修改后的文件取出来并对它们执行任何操作,除非任务很简单。”