我在使用python中的io_add_watch
監視器時遇到了問題(通過gobject)。我想在每次通知後對整個緩衝區進行非阻塞式讀取。下面的代碼(縮短了一下):gobject io monitoring + nonblocking reads
class SomeApp(object):
def __init__(self):
# some other init that does a lot of stderr debug writes
fl = fcntl.fcntl(0, fcntl.F_GETFL, 0)
fcntl.fcntl(0, fcntl.F_SETFL, fl | os.O_NONBLOCK)
print "hooked", gobject.io_add_watch(0, gobject.IO_IN | gobject.IO_PRI, self.got_message, [""])
self.app = gobject.MainLoop()
def run(self):
print "ready"
self.app.run()
def got_message(self, fd, condition, data):
print "reading now"
data[0] += os.read(0, 1024)
print "got something", fd, condition, data
return True
gobject.threads_init()
SomeApp().run()
這裏的竅門 - 當我不激活調試輸出運行程序,我沒有得到got_message
電話。當我先寫了很多東西到stderr,問題就消失了。如果我沒有寫任何與此代碼中可見的打印件不同的東西,我不會收到stdin消息信號。另一個有趣的事情是,當我嘗試運行啓用了stderr調試的同一應用程序時,但通過strace
(以檢查是否有任何錯過的fcntl/ioctl調用),問題再次出現。
所以總之:如果我先寫很多stderr沒有strace,io_watch
的作品。如果我用strace寫很多,或者根本不寫,io_watch
不起作用。
「其他init」部分需要一些時間,所以如果我在看到「hooked 2」輸出之前鍵入一些文本,然後在「ready」之後按下「ctrl + c」,則會調用get_message
回調,但讀取調用拋出EAGAIN,所以緩衝區似乎是空的。
相關標準輸入strace的日誌:
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
fcntl(0, F_GETFL) = 0xa002 (flags O_RDWR|O_ASYNC|O_LARGEFILE)
fcntl(0, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC|O_LARGEFILE) = 0
fcntl(0, F_GETFL) = 0xa802 (flags O_RDWR|O_NONBLOCK|O_ASYNC|O_LARGEFILE)
有沒有人有什麼樣的一些想法是怎麼回事嗎?
編輯:另一個線索。我試圖重構應用程序,在不同的線程中讀取數據並通過管道傳回。它「種」的作品:
...
rpipe, wpipe = os.pipe()
stopped = threading.Event()
self.stdreader = threading.Thread(name = "reader", target = self.std_read_loop, args = (wpipe, stopped))
self.stdreader.start()
new_data = ""
print "hooked", gobject.io_add_watch(rpipe, gobject.IO_IN | gobject.IO_PRI, self.got_message, [new_data])
def std_read_loop(self, wpipe, stop_event):
while True:
try:
new_data = os.read(0, 1024)
while len(new_data) > 0:
l = os.write(wpipe, new_data)
new_data = new_data[l:]
except OSError, e:
if stop_event.isSet():
break
time.sleep(0.1)
...
令人驚訝的是,如果我只是把相同的文本放在一個新的管道,一切都開始工作。問題是:
- 第一行是不是「發現」在所有 - 我只得到第二次及以後行
- 它的fugly
也許這將在給別人一個線索爲什麼會這樣?
它在真實代碼中返回True。這並不重要 - 如果它沒有被調用,它根本不會被調用 - 甚至一次。 – viraptor 2009-10-19 18:26:54