我在Python中实现了一个非阻塞读取器,我需要提高它的效率。
背景:我需要从一个子进程读取大量输出(以Popen()开头)并传递给另一个线程。读取该子进程的输出不得阻塞超过几毫秒(最好是读取可用字节所需的时间很短)。
目前,我有一个实用程序类,它接受文件描述符(stdout)和超时。我select()
和readline(1)
直到发生以下三种情况之一:
然后我将缓冲的文本返回给调用方法,调用方法用它来完成。
现在,对于真正的问题:因为我正在阅读如此多的输出,我需要提高效率。我想通过询问文件描述符有多少字节待处理然后readline([that many bytes])
来做到这一点。它应该只是传递东西,所以我实际上并不关心换行的位置,或者即使有任何问题。 我可以问一下文件描述符有多少字节可供阅读,如果是,怎么做?
我已经做了一些搜索,但是我很难找到要搜索的内容,更不用说是否可能了。
即使是正确方向的一点也会有所帮助。
注意:我正在开发Linux,但这对于“Pythonic”解决方案来说无关紧要。
答案 0 :(得分:5)
在Linux上,os.pipe()
只是管道(2)的包装器。两者都返回一对文件描述符。通常会使用lseek(2)(Python中的os.lseek()
)来重新定位文件decsriptor的偏移量,以获取可用数据量。但是,并非所有文件描述符都能够搜索。
在Linux上尝试管道上的lseek(2)将返回错误,请参阅manual page。这是因为管道或多或少是生产者和数据消费者之间的缓冲区。该缓冲区的大小取决于系统。
在Linux上,a pipe has a 64 kB buffer,这是您可以获得的最多数据。
编辑:如果您可以更改子进程的工作方式,您可以考虑使用内存映射文件或一块很好的大块共享内存。
Edit2 :使用polling objects可能比选择更快。
答案 1 :(得分:0)
这个问题似乎提供了一个可能的解决方案,但它可能需要重组。
Non-blocking read on a subprocess.PIPE in python
否则,我假设您知道一次读取N个字节的数据:
all_data = ''
while True:
data = pipe.read(1024) # Reads 1024 bytes or to end of pipe
if not data:
break
all_data += data
# Add your timeout break here
答案 2 :(得分:0)
您可以通过调用os.fstat(file_descriptor)并检查st_size属性(即写入的字节数)来找到答案。
import os
reader_file_descriptor, writer_file_descriptor = os.pipe()
os.write(writer_file_descriptor, b'I am some data')
readable_bytes = os.fstat(writer_file_descriptor).st_size
答案 3 :(得分:0)
我已经根据 spacether 的回答中的想法实现了这一点
ReactNative.NativeModules.LottieAnimationView.resume did not have a corresponding prop defined
in the mock provided to SafeModule.
ReactNative.NativeModules.LottieAnimationView.pause did not have a corresponding prop defined
in the mock provided to SafeModule.
....
import select
import os
def readLen(p):
# works on mac, might work on Linux, probably doesn't on windows (maybe return 1 in that case)
size = os.fstat(p.fileno()).st_size
return size
def readIfAny(p, timeout=1, default=None):
if select.select([p], [], [], timeout)[0]:
size = readLen(p)
if size:
return p.read(size)
return default
请注意,我在某些地方读到过,您应该尽量避免像这样直接读取和写入子进程管道,以避免死锁。但这是我目前找到的最安全的方法。
注意 2:我认为 sys.stdin.read 将在 eof 上返回 b'' 或 ''。这似乎没有引发任何异常,我仍然不知道如何判断它何时完成。
注意 3:根据它们打开的模式,您会得到字节或字符串。它也适用于标准输入、标准输出和标准错误。