【问题标题】:Python Watchdog: Is there a way to pause the observer?Python Watchdog:有没有办法暂停观察者?
【发布时间】:2013-09-13 08:03:09
【问题描述】:

我正在使用 Watchdog 监控目录并使其与 Dropbox 保持同步。

我面临这样一种情况,每次从 Dropbox 下载文件时,我都会触发上传事件,因为我需要写入 Watchdog 正在监视的目录。这是我正在使用的代码。

event_handler = UploadHandler.UploadHandler()
observer = Observer()
observer.schedule(event_handler, path=APP_PATH, recursive=True)
observer.start()

try:
    while True:
        # Apply download here   
        time.sleep(20)

except KeyboardInterrupt:
    observer.stop()

observer.join()

有没有办法在我应用下载时“暂停”观察者并在完成后再次“取消暂停”它?

【问题讨论】:

标签: python python-2.7 watchdog


【解决方案1】:

我需要暂停功能,所以我使用以下观察者:

import time
import contextlib
import watchdog.observers


class PausingObserver(watchdog.observers.Observer):
    def dispatch_events(self, *args, **kwargs):
        if not getattr(self, '_is_paused', False):
            super(PausingObserver, self).dispatch_events(*args, **kwargs)

    def pause(self):
        self._is_paused = True

    def resume(self):
        time.sleep(self.timeout)  # allow interim events to be queued
        self.event_queue.queue.clear()
        self._is_paused = False

    @contextlib.contextmanager
    def ignore_events(self):
        self.pause()
        yield
        self.resume()

然后我可以直接使用 pause()resume() 方法暂停观察者,但我的主要用例是当我只想忽略由写入我正在观看的目录引起的任何事件时,为此我使用上下文管理器:

import os
import datetime
import watchdog.events


class MyHandler(watchdog.events.FileSystemEventHandler):
    def on_modified(self, event):
        with OBSERVER.ignore_events():
            with open('./watchdir/modifications.log', 'a') as f:
                f.write(datetime.datetime.now().strftime("%H:%M:%S") + '\n')

if __name__ == '__main__':
    watchdir = 'watchdir'
    if not os.path.exists(watchdir):
        os.makedirs(watchdir)

    OBSERVER = PausingObserver()
    OBSERVER.schedule(MyHandler(), watchdir, recursive=True)
    OBSERVER.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        OBSERVER.stop()
    OBSERVER.join()

您可以通过将两个代码块保存在一个文件中、运行它并在创建的“watchdir”目录中添加/编辑/删除文件来测试这一点。您修改的时间戳将附加到“watchdir/modifications.log”。

此功能appears to be built into pyinotify,但该库仅适用于 linux,并且看门狗独立于操作系统。

【讨论】:

    【解决方案2】:

    在花了 很多时间(现在是凌晨 5 点,对任何错别字和其他东西表示歉意)之后,这里的两个答案都无济于事,我觉得自己很愚蠢,并实现了一个更简单的解决方案来满足我的需求。

    摘要(代码如下)

    1. 我没有使用自定义观察者,但你可以。
    2. 确保您的事件处理程序与您声明观察者的文件位于同一文件中。
    3. 创建一个名为 PAUSED 或类似名称的 global 或类似名称
    4. on_modified 或您在事件处理程序中使用的任何事件函数中,检查是否PAUSED is True
    5. 如果为 True,则退出,否则,继续并暂停。完成后继续。

    把它放在文件的顶部:

    global PAUSED
    PAUSED = False
    

    把它放在EventHandler.on_modified() 或任何你的事件处理程序中,以及你正在使用的任何事件函数中:

    # Retrieve global
    global PAUSED
    
    # If PAUSED, exit
    if PAUSED is True:
      return
    
    # If not, pause anything else from running and continue
    PAUSED = True
    
    # Do stuff here
    
    # Once finished, allow other things to run
    PAUSED = False
    

    推理:这将完全忽略在暂停期间尝试运行的任何内容。我需要这个,因为 Watchdog 将在每个“文件修改”事件中触发多达 5 次,因为文件仍在被写入。这确保它只触发一次、暂停,并且在其他重复事件到期之前不会恢复。

    【讨论】:

      【解决方案3】:

      您可以覆盖Observer 类的方法dispatch_events 以跳过您不想分派的事件。下面是一个例子:

      class SkipObserver(watchdog.observers.Observer):
          def __init__(self, *args):
              Observer.__init__(self, *args)
              self._skip_list = []
      
          def skip(self, event):
              with self._lock:
                  self._skip_list.append(event)
      
          def dispatch_events(self, event_queue, timeout):
              event, watch = event_queue.get(block=True, timeout=timeout)
              try:
                  if event in self._skip_list:
                      self._skip_list.remove(event)
                  else:
                      self._dispatch_event(event, watch)
              except KeyError:
                  pass
              event_queue.task_done()
      

      现在在您的示例中将 Observer 替换为 SkipObserver 并使用方法 skip 跳过事件。小心在处理程序中使用skip,因为这会以死锁结束,skip 是阻塞的,如此处实现的。在处理事件时,观察者被锁定。

      如果您想为每个处理程序指定跳过,您可以使用与上述方法类似的方法。

      【讨论】:

      • 我想这会让他输掉一些赛事。我不认为 OP 可以丢失一些信号。
      • @manu:如果你的意思是在使用 skip 时丢失一些事件(因为它是阻塞的),它不会发生。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多