Python是否有8KiB字节长的文件I/O缓存?

Python是否有8KiB字节长的文件I/O缓存?,python,windows,python-3.x,caching,file-io,Python,Windows,Python 3.x,Caching,File Io,我正在研究Python 3.6.0中的文件I/O性能。给定包含3个测试的脚本: #!python3 import random, string, time strs = ''.join(random.choice(string.ascii_lowercase) for i in range(1000000)) strb = bytes(strs, 'latin-1') inf = open('bench.txt', 'w+b') inf.write(strb) for t in rang

我正在研究Python 3.6.0中的文件I/O性能。给定包含3个测试的脚本:

#!python3

import random, string, time

strs = ''.join(random.choice(string.ascii_lowercase) for i in range(1000000))
strb = bytes(strs, 'latin-1')

inf = open('bench.txt', 'w+b')
inf.write(strb)

for t in range(3):
    inf.seek(0)
    inf.read(8191)

for t in range(3):
    inf.seek(0)
    inf.read(8192)

for t in range(3):
    inf.seek(0)
    inf.read(8193)

inf.close()
Procmon看到以下操作发生(hashtag行是我的注释):

首先,很明显python将以8KiB的倍数的块读取文件

我怀疑python实现了一个缓存缓冲区,它存储最后读取的8KiB块,如果您连续多次尝试在同一个8KiB数据块中只读,它将返回并裁剪该块

有人能确认python实际上实现了这种机制吗

如果是这种情况,这意味着如果不手动使缓存无效,python无法检测到外部应用程序对该块所做的更改。对吗?也许有一种方法可以禁用这种机制


或者,为什么8192字节的读取不能从缓存中受益?

是的,默认缓冲区大小为8k。见:

io.DEFAULT\u BUFFER\u SIZE

包含模块缓冲I/O类使用的默认缓冲区大小的
int
open()
尽可能使用文件的
blksize
(通过
os.stat()
获得)

#定义默认缓冲区大小(8*1024)/*字节*/
如果使用或包装器对文件进行更改,则缓冲区将自动更新(以二进制模式打开文件会生成
buffereDiabase
子类、或之一)

对于第二种情况,您的
seek()
调用刷新该缓冲区,因为您查找的是“当前”块范围之外的内容(当前位置位于
8192
,第二个缓冲块的第一个字节,您查找的是
0
,这是第一个缓冲块的第一个字节)。见


如果您需要从其他进程编辑基础文件,使用
seek()
是一种很好的方法,可以确保在再次尝试读取之前删除缓冲区,或者您可以忽略缓冲区并通过转到基础文件。

是的,默认缓冲区大小为8k。见:

io.DEFAULT\u BUFFER\u SIZE

包含模块缓冲I/O类使用的默认缓冲区大小的
int
open()
尽可能使用文件的
blksize
(通过
os.stat()
获得)

#定义默认缓冲区大小(8*1024)/*字节*/
如果使用或包装器对文件进行更改,则缓冲区将自动更新(以二进制模式打开文件会生成
buffereDiabase
子类、或之一)

对于第二种情况,您的
seek()
调用刷新该缓冲区,因为您查找的是“当前”块范围之外的内容(当前位置位于
8192
,第二个缓冲块的第一个字节,您查找的是
0
,这是第一个缓冲块的第一个字节)。见


如果您需要从其他进程编辑基础文件,使用
seek()
是一种很好的方法,可以确保在再次尝试读取之前删除缓冲区,或者您可以忽略缓冲区,通过访问基础文件。

您真正想做的是什么?如果要确认实际行为,请阅读源代码™.打开文件时,有一个可选的缓冲区参数,其中默认值使用操作系统默认的缓冲模式,但是您可以指定它应该是无缓冲的。您真正想做什么?如果要确认实际行为,请阅读源代码™.打开文件时,有一个可选的缓冲区参数,其中默认值使用操作系统默认缓冲模式,但是您可以指定该文件应为非缓冲。当前Windows不支持
st_blksize
。从Windows 8开始,通过
GetFileInformationByHandleEx
,在
FileStorageInfo
中的
PhysicalBytesPerSectorForPerformance
提供了等效的信息。@eryksun:不确定您为什么告诉我;-)这是Python代码开发人员需要思考的问题,不是吗?引用的文档声明“
open()
使用文件的
blksize
(如有可能,由
os.stat()
获得)”。我的评论提供了Windows当前无法进行此优化的原因,以及程序在Windows 8+中通过ctypes、cffi、Cython、PyWin32等手动实现此优化的方式。Windows当前不支持
st_blksize
。从Windows 8开始,通过
GetFileInformationByHandleEx
,在
FileStorageInfo
中的
PhysicalBytesPerSectorForPerformance
提供了等效的信息。@eryksun:不确定您为什么告诉我;-)这是Python代码开发人员需要思考的问题,不是吗?引用的文档声明“
open()
使用文件的
blksize
(如有可能,由
os.stat()
获得)”。我的评论提供了目前无法在Windows上进行此优化的原因,以及程序可以在Windows 8+中通过ctypes、cffi、Cython、PyWin32等手动实现此优化的方式。
  # Initial write
Offset: 0, Length: 1.000.000
  # The 3 8191-long reads only produce one syscall due to caching:
Offset: 0, Length: 8.192
  # However, if the read length is exactly 8192, python doesn't take advantage:
Offset: 0, Length: 8.192
Offset: 0, Length: 8.192
Offset: 0, Length: 8.192
  # Due to caching, the first syscall of the first read of the last loop is missing.
Offset: 8.192, Length: 8.192
Offset: 0, Length: 8.192
Offset: 8.192, Length: 8.192
Offset: 0, Length: 8.192
Offset: 8.192, Length: 8.192
 # Afterwards, 2 syscalls per read are produced on the 8193-long reads.
>>> import io
>>> io.DEFAULT_BUFFER_SIZE
8192