膨大なデータファイルを読み取り、そのデータをチャンクにパッケージ化して、どこかのサーバーに送信して続行するコードを継承しました。
パッケージャが失敗/停止/サーバーに接続できないなどの場合があり、データファイルが大きくなります。この時点で、ごくまれに、これらすべてを実行する小さなArchLinuxマシンがプロセスを完了できません。この時点で、データを取得し、Macで同じタスクをローカルで実行します(当面はより良いソリューションが必要です)。
ArchLinuxマシンには、私のMacでいつも発生しているように見えるエラーが発生することはありません。これは次のとおりです。
ファイルは1000
一度に1行ずつ読み取られます。これは、を使用して実現されます。これはislice
、これを行うための受け入れられた方法のようです:https ://stackoverflow.com/a/6335876/310391
問題は、Macでは、これがいくつかの行を一緒に壊してしまうことです。結果のリストは1000
長くなりますが、実際には、行の少なくとも1つは行の連結であり、ファイルは少し上(36行前、この例では正確に4096バイト)\n
からの別の行のほとんどになります。 (これは、ファイルが逆方向に読み取られるため、ある程度意味があります。以下を参照してください)。
の前後のファイルseek()
と位置を見ると、 (たとえば)とそれぞれ、バイトの読み取りサイズが得られます。tell()
islice
3530855
3651687
120832
このエラーが発生したときにファイル3530855
をpdbでシークしてから、行file.readlines(120832)
を取得しますか1092
(readlines
'サイズはヒントにすぎないため、意味があります)、変更された行は存在しません(ただし、その構成要素は含まれます)。正しいそれぞれのインデックスはそのままです)。
islice
そのファイルの読み取りまたは書き込みを行うプロセスは他にないため、たとえば、実行中にファイルがどのように「回避」されるかはわかりません。
後方リーダー(ジェネレーター)が到達する上記tell()
の前の最初の位置(ファイルは最初にジェネレーター内にあります)、行ごとにing-ジェネレーターが見つかったときのループ正常に送信された最後のタイムスタンプを含む行:islice
3530855
os.dup()
yield
break
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ボックスでは発生しません。低レベルのファイル操作は私のパンとバターではありません。ここでジェネレーターと組み合わせると、何かが欠けているに違いないと思います。誰かがここで次のデバッグ手順を提案したり、この不一致の原因についてのヒントを提供したりできますか?