kqueue 實現文件操做監控

kqueue

最近接觸到一些比較底層的東西,感受跟操做系統原理結合起來看,理解起來會更容易。html

在使用 kevent 的時候遇到了一個很奇怪的問題,在 stackoverflow 上面提了個問題fileno errors when calling kevent function麻煩有知道的能夠回答一下python

Stackoverflow 上的大神給我了點提示,若是直接使用 fd = open('test').fileno(),確實是能夠取獲得打開文件的文件描述符,可是文件自己 file object 會由於沒有變量引用而被垃圾回收器回收。我試了一下手動關閉垃圾回收器暫時沒有成功,可是用變量引用 fileobject 後確實能解決問題。此處仍是有疑惑。linux

在調試 kevent 的時候遇到了不少問題,直接看 Python 的 C 語言源代碼或者 PyPy 的源碼會一會兒清晰不少。app

例如在 Python 2.7.10 的 selectmodule.c 中,kqueue_event_init 函數在處理 ident 的時候會首先判斷是否是長整形,若是不是長整型,再嘗試用 PyObject_AsFileDescriptor 來做爲文件描述符賦值。這個函數位於 fileobject.c 中,它會判斷咱們傳入的 ident 中有沒有調用 fileno 方法,若是有,就先執行這個方法,而後將返回的文件描述符返回給 kqueue_event_init。socket

這裏在 CPython 中,kqueue 和 kevent 相關的操做經過直接調用系統 API 而成,在 PyPy 中,它經過 RPython 的 Foreign Function Interface 來調用系統 API。ide


kqueue 是 BSD 系統下的一套消息接口,其基本原理與 epoll 類似,它避免了遍歷全部被監控的文件描述符的操做。函數

咱們在 Python 中可使用 select 庫調用系統接口來實現 kqueue,它有一個 kevent 對象和一個 kqueue 對象,參見參考資料。操作系統

import select

fd = open('test')
kq = select.kqueue()

# 規定咱們所要作的操做,分別爲 添加事件,使能該事件,事件被取出後恢復標記
flags = select.KQ_EV_ADD | select.KQ_EV_ENABLE | select.KQ_EV_CLEAR

# 要監控的事件類型,分別爲 刪除,寫入,追加寫入,重命名
fflags = select.KQ_NOTE_DELETE | select.KQ_NOTE_WRITE | select.KQ_NOTE_EXTEND \
         | select.KQ_NOTE_RENAME
# 初始化該事件
ev = select.kevent(fd, filter=select.KQ_FILTER_VNODE, flags=flags, fflags=fflags)

while 1:
    # 將上述事件加入到 kqueue 中,此時程序被阻塞,直到事件發生,或者咱們能夠設置 timeout 字段
    revents = kq.control([ev], 1, None)
    # 取出返回的事件
    for e in revents:
        # 若是是 EXTEND 事件,下同
        if e.fflags & select.KQ_NOTE_EXTEND:
        # 打印 EXTEND,下同
            print 'extend'
        elif e.fflags & select.KQ_NOTE_WRITE:
            print 'write'
        elif e.fflags & select.KQ_NOTE_RENAME:
            print 'rename'
        elif e.fflags & select.KQ_NOTE_DELETE:
            print 'delete'
        else:
            print e

監控文件系統有個很著名的 watchdog 庫,它在 linux 上採用了 inotify,在 MAC 上除了 kqueue 之外還可用 FSEvents 來監控。調試

inotify 和 FSEvent 都是專門用於監控文件系統的,能監控的文件操做類型更多,而 epoll 和 kqueue 除了文件系統以外,還能夠監控 sockets 或者其餘的 I/O。詳見 Difference between inotify and epoll。code

參考資料

  1. select — Waiting for I/O completion

  2. epoll 或者 kqueue 的原理是什麼?

  3. KQUEUE(2)

  4. errno.h

  5. watchdog 0.8.3

  6. Difference between inotify and epoll

相關文章
相關標籤/搜索