我在 ubuntu 中工作,需要监视目录树中的新子目录和文件。这些由 rsync 填充;不到一秒即可添加数十个子目录和数百个文件。我正在考虑几个选择:
选项 1:使用 python 的 inotify.adapters.InotifyTree() 监视树。但文档包含此警告:“重要的:递归监视路径不是内核提供的功能。相反,我们人为地实现它。当收到目录创建的事件时,我们会即时为子目录创建监视。这意味着存在潜在的竞争条件:如果在您(使用 event_gen() 循环)有机会观察它之前创建了一个目录并在内部创建了一个文件或目录,那么您将遇到问题:如果它是一个文件,那么您将错过与其创建相关的事件,但是,如果它是一个目录,那么您不仅会错过那些创建事件,而且该库也会错过它们,并且无法添加监视他们。”
选项 2:使用 '--recursive' 选项通过 linux inotifywatch 实用程序监视树。该文档包括以下警告:“警告:如果您在监视一棵大树的根目录时使用此选项,则可能需要相当长的时间才能建立所有 inotify 监视,并且此时将不会收到事件。”
您认为这两个选项中哪一个不太可能错过新的子目录和文件?我的感觉是,选项 2 可能更可靠,因为 inotifywatch (可能)是用“C”实现的。谢谢!
答案1
让我们从正确理解这个问题开始。您在两本手册中读到的警告均来自于“限制和警告”男人7 inotify:https://man7.org/linux/man-pages/man7/inotify.7.html
这来自内核限制,因此了解这一点很重要两个都即使它们各自的手册没有提及某些软件,也可能存在相同的问题。
我自己的猜测是,notifywatch 的手册没有提到竞争条件,因为它不太可能与大多数用户相关。 手册指出:
notifywatch
使用 Linux 的 inotify(7) 接口侦听文件系统事件,然后输出每个文件或目录上收到的事件的摘要计数。
如果该软件跳过新子目录中的一些文件创建事件,它仍然会执行其应该执行的操作:报告统计信息。
你能做什么?
我认为这两种解决方案都不能保证像您似乎需要的那样完美,如果我知道竞争条件可能会成为问题,我永远不会让竞争条件破坏我的软件。不要只是“希望”一切都会好起来!
再次来自 inotify 7 手册:
然而,健壮的应用程序应该考虑到以下事实:监视逻辑中的错误或下述类型的竞争可能会使缓存与文件系统状态不一致。明智的做法可能是进行一些一致性检查,并在检测到不一致时重建缓存。
在您的情况下,明智的做法是使用类似于 1 或 2 的选项以及围绕竞争条件的代码。当您检测到正在创建新目录时:
- 记下新目录。
- 等到您阅读完所有可用的 inotify 事件后
- 然后扫描目录 (
pathlib.Path.iterdir()
) 以查看是否在竞争条件下遗漏了任何文件。
怎样等待?
等待所有可用的 inotify 事件是很棘手的。使用选项 1(来自 PyPi 的 inotify),您可以使用短超时获取所有可用事件:
gen = i.event_gen(yield_nones=False, timeout_s=0.1)
当您有新的目录要扫描时,您可以设置一个较短的超时时间,并在超时时扫描这些目录。当您没有要扫描的新目录时,您可以在没有超时的情况下使用它(永不超时)。