2

我继承了一些代码,这些代码读取大量数据文件并将这些数据打包成块,将其发送到某处的服务器并继续执行。

有时打包程序失败/死亡/无法联系服务器等,数据文件变大。在这一点上,执行所有这些操作的小型 ArchLinux 机器很少会无法完成该过程 - 此时我会在我的 Mac 上获取数据并在本地执行相同的任务(同时需要更好的解决方案)。

ArchLinux 机器永远不会出现我的 Mac 似乎总是遇到的相同错误,即:

该文件1000一次读取行,这是使用 实现的islice,这似乎是一种可接受的方式:https ://stackoverflow.com/a/6335876/310391

问题在于,在 Mac 上,这最终会将几行代码拼凑在一起。结果列表很1000长,但至少其中一行实际上是一行的串联,没有\n, 和另一行的大部分从稍微向上(36 行返回,在本例中正好 4096 字节)文件(这在向后读取文件时是有道理的,见下文)。

查看 之前和之后的文件seek()tell()位置islice,我分别得到(例如)3530855和字节3651687的读取大小。120832

如果我在 pdb 中遇到此错误时将文件返回到3530855,然后file.readlines(120832)我会得到1092行(readlines' size 只是一个提示,所以这是有道理的),并且 munged 行不存在(但它的组成部分在各自正确的索引中完好无损)。

没有其他进程从该文件读取或写入该文件,因此我看不到它在执行时会如何“分流” islice,例如。

tell()前面给出的第一个位置islice,上面给出3530855的后向阅读器(生成器)(文件是os.dup()'d,首先,在生成器内部)yield逐行执行 - 生成器breaks 找到时的循环包含它成功发送的最后一个时间戳的行:

for line in BackwardsFileReader(fp):
    if somecondition:
        break

def BackwardsReader(seekfile, size=4096, pos=-1):
    """Read a file line by line, backwards"""
    fd = os.dup(seekfile.fileno())
    buf = ""
    whence = os.SEEK_END if pos < 0 else os.SEEK_SET

    with os.fdopen(fd) as readfile:
        readfile.seek(0, os.SEEK_END)
        if readfile.tell() == 0:
            # File is empty, bail.
            return
        readfile.seek(pos, whence)
        buf = readfile.read(size)
        readfile.seek(pos, whence)
        newline_pos = buf.find("\n")
        if newline_pos != -1:
            trailing_newline = True
            buf = buf[:newline_pos]
        else:
            trailing_newline = False

        while 1:
            newline_pos = buf.rfind("\n")
            pos = readfile.tell()
            if newline_pos != -1:
                # Found a newline
                line = buf[newline_pos+1:]
                # Seek the original file to the end of buf
                seekfile.seek(pos + len(buf), os.SEEK_SET)
                buf = buf[:newline_pos]
                if pos or newline_pos or trailing_newline:
                    line += "\n"
                yield line
            elif pos:
                # Need to fill buffer
                toread = min(size, pos)
                readfile.seek(-toread, 1)
                buf = readfile.read(toread) + buf
                readfile.seek(-toread, 1)
                if pos == toread:
                    buf = "\n" + buf
            else:
                # Start-of-file
                seekfile.seek(0)
                return

如果我不费心对文件进行切片,并阅读全部内容(在我的 Mac 上),问题仍然会发生,但不是在同一个地方,而且频率较低。

我唯一能想到的是,生成器可能正在进一步向后推进文件(4096 字节,缓冲区大小),而 islice 正在向前读取文件......奇怪的是这在 Linux 机器上从未发生过。低级文件操作不是我的面包和黄油,当在这里与生成器结合使用时,我想我一定会遗漏一些东西 - 任何人都可以在这里建议下一个调试步骤,或者提供有关可能导致这种差异的提示吗?

4

0 回答 0