在select()之后读取 - 在管道上阻塞

时间:2013-03-23 10:03:22

标签: python unix

我的Python程序需要从多个不同的文件描述符中复用读取。其中一些是子进程的stdout / stderr描述符;其他是与inotify电话相关联的文件描述符。

我的问题是能够在select()之后进行“非阻塞”[1]阅读。根据{{​​3}},select()报告准备写入的套接字“保证在写入高达PIPE_BUF字节时不会阻塞”。

我认为没有这样的保证对于读取是有意义的,因为select()报告在内核管道缓冲区中有等待准备的数据并不意味着你可以继续前进到{{1}因为那里可能只有几个字节。

这意味着当我在套接字上调用.read(socket.PIPE_BUF)时,我可以得到实际上是死锁的东西,因为一些子进程很少产生输出。

这有什么办法吗?我目前的解决方法是在其上调用read(),我很幸运,我正在读取的所有内容都有逐行输出。从这样的管道读取时,readline()是否有任何用处,因为没有办法知道你可以安全地读取多少字节而不会阻塞?

[1]我知道这与O_NONBLOCK套接字不同

2 个答案:

答案 0 :(得分:3)

可以继续read每个管道和套接字:您将获得现在可用的任何数据:

>>> import os
>>> desc = os.pipe()
>>> desc
(3, 4)
>>> os.write(desc[1], 'foo')
3
>>> os.read(desc[0], 100)
'foo'
>>> os.read(desc[0], 100)

[挂起,因为没有可用的输入,用^ C中断]

...
KeyboardInterrupt
>>> os.write(desc[1], 'a')
1
>>> os.read(desc[0], 100)
'a'
>>> 

答案 1 :(得分:0)

作为替代方案,我遇到了完全相同的问题,并使用readline(1)并将其附加到内部缓冲区来解决它,直到readline返回一个我感兴趣的字符(换行符,空格等) )。

更多细节:我在文件描述符上调用select(),然后在select返回的任何文件描述符上调用readline(1),将该char附加到缓冲区,并重复直到readline返回我想要的内容。然后我退回了缓冲区,清除了它并继续前进。顺便说一下,我还返回了一个布尔值,让调用方法知道我返回的数据是否为空,因为读取错误只是因为没有完成。

我还实现了一个在超时时标记化的版本。如果我在没有找到换行符或EOF的情况下缓冲x ms,请继续并返回缓冲区。

我目前正试图找出是否有办法询问文件描述符等待读取的字节数,然后只是readline([that many bytes]) ...

希望有所帮助。