5

在我的应用程序中,我需要查看新文件的目录。流量非常大,每秒至少会出现数百个新文件。目前,我正在使用带有这种想法的繁忙循环:

while True:
  time.sleep(0.2)
  if len(os.listdir('.')) > 0:
    # do stuff

运行分析后,我看到很多时间都花在了睡眠中,我想知道是否应该将其更改为使用轮询。

我正在尝试使用其中一个可用的类select来轮询我的目录,但我不确定它是否真的有效,或者我只是做错了。

我的目录有一个 fd:

fd = os.open('.', os.O_DIRECT)

然后我尝试了几种方法来查看目录何时更改。例如,我尝试过的一件事是:

poll = select.poll()
poll.register(fd, select.POLLIN)

poll.poll()  # returns (fd, 1) meaning 'ready to read'

os.read(fd, 4096) # prints largely gibberish but i can see that i'm pulling the files/folders contained in the directory at least

poll.poll()  # returns (fd, 1) again

os.read(fd, 4096) # empty string - no more data

为什么 poll() 表现得好像有更多信息要阅读?我假设它只会在目录中发生更改的情况下这样做。

我在这里尝试做的事情甚至可能吗?

如果没有,还有其他更好的选择while True: look for changes吗?

4

6 回答 6

6

FreeBSD 和 Mac OS X 提供了一个类似 inotify 的方法,称为 kqueue。在 FreeBSD 机器上键入 man 2 kqueue 以获取更多信息。对于 Freebsd 上的 kqueue,您可以在http://people.freebsd.org/~dwhite/PyKQueue/上获得 PyKQueue ,不幸的是没有积极维护,因此您的里程可能会有所不同。

于 2009-09-22T07:24:01.353 回答
3

为什么不将 Python 包装器用于监视文件更改的库之一,例如gamin或 inotify(搜索 pyinotify,我只允许以新用户的身份发布一个超链接......) - 这肯定会更快,而且低级的东西已经在 C 级为你完成了,使用内核接口......

于 2009-07-24T15:24:38.210 回答
1

运行分析后,我看到很多时间都花在了睡眠中,我想知道是否应该将其更改为使用轮询。

看起来您已经通过定期检查状态进行了同步轮询不要担心“花费”的时间sleep,它不会占用 CPU 时间。它只是将控制权传递给操作系统,操作系统会在请求的超时后唤醒进程。

您可以考虑使用一个库来监听操作系统提供的文件系统更改通知的异步事件循环,但首先要考虑它在这种特殊情况下是否能给您带来任何真正的好处。

于 2009-07-24T23:24:14.720 回答
0

您可能想看看select.kqueue - 我没有使用它,但我相信在 BSD 下 kqueue 是正确的接口,因此您可以监视文件/目录并仅在它们更改时被回调

于 2009-09-22T12:58:52.210 回答
0

我已经编写了一个库和一个 shell 工具来为你处理这个问题。

http://github.com/gorakhargosh/watchdog

虽然,kqueue 是一种非常重量级的监视目录的方法,如果您可以测试和检查您可能遇到的任何性能问题,我将不胜感激。补丁也很受欢迎。

HTH。

于 2010-12-15T09:26:56.290 回答
0

如果您的系统有 select.kqueue() 这是解决这个问题的好方法,例如:

import os
import select

dn = '/tmp'
kq = select.kqueue()
fd = os.open(dn, os.O_DIRECT)

last = set(os.listdir(dn))

kevent = select.kevent(fd, filter=select.KQ_FILTER_VNODE,
    flags=select.KQ_EV_ADD | select.KQ_EV_CLEAR,
    fflags=select.KQ_NOTE_WRITE)

while True:
    if kq.control([kevent], 1):
        this = set(os.listdir(dn))

        added = list(this.difference(last))
        if added:
            print('  added: %s' % ' '.join(added))

        removed = list(last.difference(this))
        if removed:
            print('removed: %s' % ' '.join(removed))

        last = this
于 2020-03-26T22:19:04.523 回答