使用select / poll / kqueue / kevent来查看新文件的目录

时间:2009-07-22 14:13:57

标签: python asynchronous freebsd polling

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

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吗?

6 个答案:

答案 0 :(得分:6)

FreeBSD以及Mac OS X提供了一种名为kqueue的inotify模拟。在FreeBSD机器上键入man 2 kqueue以获取更多信息。对于Freebsd上的kqueue,你可以在http://people.freebsd.org/~dwhite/PyKQueue/获得PyKQueue,但遗憾的是没有积极维护,所以你的里程可能会有所不同。

答案 1 :(得分:3)

为什么不在其中一个库中使用Python包装来监控文件更改,例如gamin或inotify(搜索pyinotify,我只允许以新用户的身份发布一个超链接...) - 肯定会更快,低级别的东西已经在C级别上完成,使用内核接口......

答案 2 :(得分:1)

  

在运行性能分析后,我看到很多时间都在睡眠中,我想知道是否应该更改它以使用轮询。

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

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

答案 3 :(得分:0)

你可能想看一下select.kqueue - 我没有用它,但是kqueue是BSD下的正确接口我相信你可以监视文件/目录并且只在当时和他们改变了

答案 4 :(得分:0)

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

http://github.com/gorakhargosh/watchdog

虽然,kqueue是监控目录的一种非常重要的方式 如果您可以测试和结帐任何表现,我将不胜感激 你可能遇到的问题。补丁也是受欢迎的。

HTH。

答案 5 :(得分: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