【问题标题】:How do I async pickle a lot of files with aiofiles?如何使用 aiofiles 异步腌制大量文件?
【发布时间】:2020-01-14 22:44:20
【问题描述】:

我有一个我想写的列表,data,每个项目都有一个文件,如下所示:

for i,chunk in enumerate(data):
    fname = ROOT / f'{i}.in'
    with open(fname, "wb") as fout:
        dill.dump(chunk, fout)

由于数据列表可能很长,并且我正在写入网络存储位置,因此我花费大量时间等待 NFS 中的迭代,如果可能。

我现在的东西基本上是这样的:

import dill
import asyncio
import aiofiles
from pathlib import Path

ROOT = Path("/tmp/")

data = [str(i) for i in range(500)]

def serialize(data):
  """
  Write my data out in serial
  """
  for i,chunk in enumerate(data):
    fname = ROOT / f'{i}.in'
    print(fname)
    with open(fname, "wb") as fout:
        dill.dump(chunk, fout)

def aserialize(data):
  """
  Same as above, but writes my data out asynchronously
  """
  fnames = [ROOT / f'{i}.in' for i in range(len(data))]
  chunks = data
  async def write_file(i):
    fname = fnames[i]
    chunk = chunks[i]
    print(fname)
    async with aiofiles.open(fname, "wb") as fout:
        print(f"written: {i}")
        dill.dump(chunk, fout)
        await fout.flush()
  loop = asyncio.get_event_loop()
  loop.run_until_complete(asyncio.gather(*[write_file(i) for i in range(len(data))]))

现在,当我测试写入时,这看起来足够快,值得在我的 NFS 上使用:

# test 1
start = datetime.utcnow()
serialize(data)
end = datetime.utcnow()
print(end - start)
# >>> 0:02:04.204681

# test 3
start = datetime.utcnow()
aserialize(data)
end = datetime.utcnow()
print(end - start)
# >>> 0:00:27.048893
# faster is better.

但是当我真正 /de/-serialize 我写的数据时,我发现它可能很快,因为它没有写任何东西:

def deserialize(dat):
  tmp = []
  for i in range(len(dat)):
    fname = ROOT / f'{i}.in'
    with open(fname, "rb") as fin:
      fo = dill.load(fin)
    tmp.append(fo)
  return tmp

serialize(data)
d2 = deserialize(data)
d2 == data
# True

好,然而:

aserialize(data)
d3 = deserialize(data)
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in deserialize
  File "...python3.7/site-packages/dill/_dill.py", line 305, in load
    obj = pik.load()
EOFError: Ran out of input

即异步写入的文件为空。难怪这么快。

我怎样才能将我的列表异步地挖掘/腌制到文件中并让它们实际写入?我想我需要以某种方式等待 dill.dump 吗?我以为 fout.flush 会处理这个问题,但似乎没有。

【问题讨论】:

  • 在 aiofiles write 方法是协程。这意味着必须等待f.write()。 dill 库对此一无所知,并认为您传递的 fin 是一个常规文件。你应该得到“RuntimeWarning: coroutine was never waiting”。 @sanyash 的答案应该让它工作。但不确定它是否会更快

标签: python async-await dill python-aiofiles


【解决方案1】:

我将dill.dump(chunk, fout) 行更改为await fout.write(dill.dumps(chunk)),并将数据写入文件并正确反序列化。似乎dill.dump 仅适用于调用file.write 方法而没有await 关键字的常规同步文件。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-05
  • 2015-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多