如何 asyncio 安排文件系统统计操作?

cfi*_*cfi 6 python stat python-3.x python-asyncio

将一些代码转换为使用asyncio,我想尽快将控制权交还给asyncio.BaseEventLoop。这意味着避免阻塞等待。

如果没有 asyncio,我会使用os.stat()pathlib.Path.stat()获取例如文件大小。有没有办法用 asyncio 有效地做到这一点?

我可以结束stat()通话,使其成为类似于此处描述的未来吗?

Jul*_*ard 6

os.stat()转换为stat系统调用:

$ strace python3 -c 'import os; os.stat("/")'
[...]
stat("/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[...]
Run Code Online (Sandbox Code Playgroud)

这是阻塞的,并且无法获得非阻塞的stat系统调用。

asyncio通过使用已经存在的非阻塞系统调用提供非阻塞 I/O(参见man fcntl,带有它的O_NONBLOCK标志,或ioctl),所以asyncio不是使系统调用异步,它以一种很好的方式公开已经异步的系统调用。

仍然可以使用漂亮的ThreadPoolExecutor抽象来stat使用线程池并行执行阻塞调用。

但是您可以先考虑一些其他参数:

  • 根据strace -T, statis fast: stat("/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000007>,可能比启动和同步线程快。
  • stat 在很多情况下可能会受到 IO 限制,因此使用更多 CPU 无济于事
  • 执行并行 I/O 可能会破坏对随机访问的良好顺序访问,在这种情况下,物理硬盘驱动器可能会更慢。

但是,stat使用线程池也有很多可能让您的s 更快,就像您正在使用分布式文件系统一样。

你也可以看看functools.lru_cache:如果你在stat同一个文件或目录上做多个,并且你确定它没有改变,缓存结果可以避免系统调用。

总而言之,“保持简单”,“os.stat”获取文件大小的有效方法。