You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python计算SHA256时POSIX_FADV_DONTNEED的效果实测:不建议使用

POSIX_FADV_DONTNEED 实测性能记录

更新:经过更多测试后,本文主要用于记录实测结果。

TL;DR:不建议使用POSIX_FADV_DONTNEED,不使用该标志时速度最快,在AMD64架构下该标志甚至未被内核遵守。

测试环境

  • 树莓派4,USB3.0连接5TB机械硬盘,ext4文件系统
  • 该配置下使用1线程速度最优,推测原因是机械硬盘特性

实测结果

本次测试场景为计算目录树中所有文件的SHA256哈希值(无需输入加密密码即可检查多个restic仓库):

  • 监控工具(nmon、node_exporter)显示使用POSIX_FADV_DONTNEED时磁盘读取速度几乎翻倍。该标志的作用是告知内核无需将读取的数据保留在缓存中,理论上因文件仅读取一次,可避免污染系统缓存导致其他数据缓存失效。
  • 实际测速与监控数据存在差异:不使用POSIX_FADV_DONTNEED时,读取速度为60-90MB/s;使用时为155-175MB/s,但time命令统计的实际耗时完全不同。

每次测试前均执行缓存清理命令:

sync; echo 3 > /proc/sys/vm/drop_caches

树莓派4测试数据

  • 使用posix_fadvise(fd, 0, bytesRead):耗时37秒,监控显示磁盘速度慢
  • 使用posix_fadvise(fd, 0, 0):监控显示磁盘速度翻倍,但实际耗时1分08秒
  • 使用空实现的posix_fadvise函数:仅耗时29秒,是最快的结果

注:树莓派上磁盘速度显示不准确,AMD64平台的监控数据更准确;但树莓派上VictoriaMetrics显示使用POSIX_FADV_DONTNEED时缓存未增长,说明该标志被内核遵守。

其他场景补充测试

  • SSD高性能云虚拟机:使用4线程时,POSIX_FADV_DONTNEED会导致速度慢5倍(测试前同样执行echo 3 > /proc/sys/vm/drop_caches清理缓存)
  • USB3.0连接机械硬盘的物理机:单线程使用POSIX_FADV_DONTNEED耗时1分25秒;清理缓存后不使用该标志仅耗时12秒,速度差7倍

2023.09.20 AMD64架构更新

VictoriaMetrics显示AMD64架构下POSIX_FADV_DONTNEED未被内核遵守,缓存仍在增长:

  • 使用posix_fadvise(fd, 0, bytesRead)与空实现函数的time结果无明显差异
  • 使用posix_fadvise(fd, 0, 0)耗时2分31秒

测试代码

import os
import subprocess
import hashlib
import concurrent.futures
import sys
import ctypes

# Constants for posix_fadvise
POSIX_FADV_DONTNEED = 4

base_directory = '/home/pi/5TB'
num_threads = 1  # Adjust the number of threads as needed
# Define posix_fadvise function
def posix_fadvise(fd, offset, length):
    #return #uncomment and speed will be much slower
    libc = ctypes.CDLL("libc.so.6")
    ret = libc.posix_fadvise(fd, offset, length, POSIX_FADV_DONTNEED)
    if ret != 0:
        raise OSError(f"posix_fadvise failed with error code {ret}")

def calculate_sha256(file_path):
    try:
        # Calculate the SHA256 checksum of the file
        sha256_hash = hashlib.sha256()
        bytesRead = 0  # Initialize the counter for bytes read
        with open(file_path, 'rb') as f:
            fd = f.fileno()  # Get file descriptor
            # Advise the kernel that we don't need the file data anymore
            #posix_fadvise(fd, 0, 0)            
            while True:
                data = f.read(65536)  # Read in 64KB chunks
                if not data:
                    break
                bytesRead += len(data)
                sha256_hash.update(data)
                posix_fadvise(fd, 0, bytesRead)     
        
        checksum = sha256_hash.hexdigest()

        # Check if the checksum matches the filename
        filename = os.path.basename(file_path)
        if checksum != filename:
            sys.stderr.write(f"Error: Checksum mismatch for file '{file_path}'\n")
        
        return file_path
    except Exception as e:
        sys.stderr.write(f"Error processing file '{file_path}': {str(e)}\n")
        return None

def process_files_in_directory(directory):
    files = [os.path.join(directory, filename) for filename in os.listdir(directory) if os.path.isfile(os.path.join(directory, filename))]

    results = []
    with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
        for file in executor.map(calculate_sha256, files):
            if file is not None:
                results.append(file)

    return results

if __name__ == "__main__":
    checked_count = 0
    for root, _, _ in os.walk(base_directory):
        checked_files = process_files_in_directory(root)
        checked_count += len(checked_files)
        if checked_count % 100 == 0:
            sys.stdout.write(f"Checked {checked_count} files...\n")
            sys.stdout.flush()  # Flush the stdout buffer to write immediately                                                                

    sys.stdout.write(f"Checked {checked_count} files in total.\n")

内容的提问来源于stack exchange,提问作者Hannes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:55:08