使用select/poll/kqueue/kevent监视目录中新文件
在我的应用程序中,我需要监控一个文件夹,看看有没有新文件出现。这个文件夹的流量非常大,每秒至少会有几百个新文件生成。目前,我使用的是一种忙等待的循环,类似这样的思路:
while True:
time.sleep(0.2)
if len(os.listdir('.')) > 0:
# do stuff
经过性能分析,我发现我在“睡眠”这部分花费了很多时间,我在想是不是应该改成轮询的方式来处理。
我尝试使用select
中可用的类来轮询我的文件夹,但我不确定这样做是否有效,或者我是不是用错了方法。
我通过以下方式获取了文件夹的文件描述符:
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 个回答
为什么不使用一个Python的封装库来监控文件变化,比如gamin或者inotify(可以搜索一下pyinotify,我作为新用户只能发一个链接...)呢?这样做肯定会更快,因为底层的工作已经用C语言处理好了,直接调用内核接口就行了...
FreeBSD和Mac OS X有一个类似于inotify的功能,叫做kqueue。如果你在FreeBSD机器上输入命令“man 2 kqueue”,可以获取更多信息。关于FreeBSD上的kqueue,你可以使用PyKQueue,网址是http://people.freebsd.org/~dwhite/PyKQueue/,不过这个工具并没有得到积极维护,所以使用效果可能会有所不同。
在进行性能分析后,我发现有很多时间花在了休眠上,我在想是否应该改成轮询。
看起来你已经在做同步轮询了,也就是定期检查状态。别担心在sleep
中“花费”的时间,这不会占用CPU的时间。它只是把控制权交给操作系统,等到设定的时间到了,操作系统再把这个进程唤醒。
你可以考虑使用异步事件循环,利用一个库来监听操作系统提供的文件系统变化通知,但在这之前,先想想这样做在你当前的情况下是否真的有好处。