2

膨大なデータファイルを読み取り、そのデータをチャンクにパッケージ化して、どこかのサーバーに送信して続行するコードを継承しました。

パッケージャが失敗/停止/サーバーに接続できないなどの場合があり、データファイルが大きくなります。この時点で、ごくまれに、これらすべてを実行する小さなArchLinuxマシンがプロセスを完了できません。この時点で、データを取得し、Macで同じタスクをローカルで実行します(当面はより良いソリューションが必要です)。

ArchLinuxマシンには、私のMacでいつも発生しているように見えるエラーが発生することはありません。これは次のとおりです。

ファイルは1000一度に1行ずつ読み取られます。これは、を使用して実現されます。これはislice、これを行うための受け入れられた方法のようです:https ://stackoverflow.com/a/6335876/310391

問題は、Macでは、これがいくつかの行を一緒に壊してしまうことです。結果のリストは1000長くなりますが、実際には、行の少なくとも1つは行の連結であり、ファイルは少し(36行、この例では正確に4096バイト)\nからの別の行のほとんどになります。 (これは、ファイルが逆方向に読み取られるため、ある程度意味があります。以下を参照してください)。

の前後のファイルseek()と位置を見ると、 (たとえば)とそれぞれ、バイトの読み取りサイズが得られます。tell()islice35308553651687120832

このエラーが発生したときにファイル3530855をpdbでシークしてから、行file.readlines(120832)を取得しますか1092readlines'サイズはヒントにすぎないため、意味があります)、変更された行は存在しません(ただし、その構成要素は含まれます)。正しいそれぞれのインデックスはそのままです)。

isliceそのファイルの読み取りまたは書き込みを行うプロセスは他にないため、たとえば、実行中にファイルがどのように「回避」されるかはわかりません。

後方リーダー(ジェネレーター)が到達する上記tell()の前の最初の位置(ファイルは最初にジェネレーター内にあります)、行ごとにing-ジェネレーターが見つかったときのループ正常に送信された最後のタイムスタンプを含む行:islice3530855os.dup()yieldbreak

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で)全体を読んでも問題は発生しますが、同じ場所では発生せず、頻度も低くなります。

私が考えることができる唯一のことは、isliceがファイルを順方向に読み取っている間、ジェネレーターがファイルをさらに逆方向(4096バイト、バッファーサイズ)に進めている可能性があるということです...奇妙なことに、これはLinuxボックスでは発生しません。低レベルのファイル操作は私のパンとバターではありません。ここでジェネレーターと組み合わせると、何かが欠けているに違いないと思います。誰かがここで次のデバッグ手順を提案したり、この不一致の原因についてのヒントを提供したりできますか?

4

0 に答える 0