为什么从文件中读取 1 个字节比读取 2、3、4、... 字节慢 20 倍?

2024-01-29

我一直试图理解之间的权衡read and seek。对于小的“跳跃”,读取不需要的数据比使用跳过它更快seek.

在计时不同的读取/查找块大小以找到临界点时,我遇到了一个奇怪的现象:read(1)大约慢20倍read(2), read(3)等。对于不同的读取方法,此效果是相同的,例如read() and readinto().

为什么会这样呢?

在计时结果中搜索以下第 2/3 行:

2 x buffered 1 byte readinto bytearray

环境:

Python 3.5.2 |Continuum Analytics, Inc.| (default, Jul  5 2016, 11:45:57) [MSC v.1900 32 bit (Intel)]

计时结果:

Non-cachable binary data ingestion (file object blk_size = 8192):
- 2 x buffered 0 byte readinto bytearray:
      robust mean: 6.01 µs +/- 377 ns
      min: 3.59 µs
- Buffered 0 byte seek followed by 0 byte readinto:
      robust mean: 9.31 µs +/- 506 ns
      min: 6.16 µs
- 2 x buffered 4 byte readinto bytearray:
      robust mean: 14.4 µs +/- 6.82 µs
      min: 2.57 µs
- 2 x buffered 7 byte readinto bytearray:
      robust mean: 14.5 µs +/- 6.76 µs
      min: 3.08 µs
- 2 x buffered 2 byte readinto bytearray:
      robust mean: 14.5 µs +/- 6.77 µs
      min: 3.08 µs
- 2 x buffered 5 byte readinto bytearray:
      robust mean: 14.5 µs +/- 6.76 µs
      min: 3.08 µs
- 2 x buffered 3 byte readinto bytearray:
      robust mean: 14.5 µs +/- 6.73 µs
      min: 2.57 µs
- 2 x buffered 49 byte readinto bytearray:
      robust mean: 14.5 µs +/- 6.72 µs
      min: 2.57 µs
- 2 x buffered 6 byte readinto bytearray:
      robust mean: 14.6 µs +/- 6.76 µs
      min: 3.08 µs
- 2 x buffered 343 byte readinto bytearray:
      robust mean: 15.3 µs +/- 6.43 µs
      min: 3.08 µs
- 2 x buffered 2401 byte readinto bytearray:
      robust mean: 138 µs +/- 247 µs
      min: 4.11 µs
- Buffered 7 byte seek followed by 7 byte readinto:
      robust mean: 278 µs +/- 333 µs
      min: 15.4 µs
- Buffered 3 byte seek followed by 3 byte readinto:
      robust mean: 279 µs +/- 333 µs
      min: 14.9 µs
- Buffered 1 byte seek followed by 1 byte readinto:
      robust mean: 279 µs +/- 334 µs
      min: 15.4 µs
- Buffered 2 byte seek followed by 2 byte readinto:
      robust mean: 279 µs +/- 334 µs
      min: 15.4 µs
- Buffered 4 byte seek followed by 4 byte readinto:
      robust mean: 279 µs +/- 334 µs
      min: 15.4 µs
- Buffered 49 byte seek followed by 49 byte readinto:
      robust mean: 281 µs +/- 336 µs
      min: 14.9 µs
- Buffered 6 byte seek followed by 6 byte readinto:
      robust mean: 281 µs +/- 337 µs
      min: 15.4 µs
- 2 x buffered 1 byte readinto bytearray:
      robust mean: 282 µs +/- 334 µs
      min: 17.5 µs
- Buffered 5 byte seek followed by 5 byte readinto:
      robust mean: 282 µs +/- 338 µs
      min: 15.4 µs
- Buffered 343 byte seek followed by 343 byte readinto:
      robust mean: 283 µs +/- 340 µs
      min: 15.4 µs
- Buffered 2401 byte seek followed by 2401 byte readinto:
      robust mean: 309 µs +/- 373 µs
      min: 15.4 µs
- Buffered 16807 byte seek followed by 16807 byte readinto:
      robust mean: 325 µs +/- 423 µs
      min: 15.4 µs
- 2 x buffered 16807 byte readinto bytearray:
      robust mean: 457 µs +/- 558 µs
      min: 16.9 µs
- Buffered 117649 byte seek followed by 117649 byte readinto:
      robust mean: 851 µs +/- 1.08 ms
      min: 15.9 µs
- 2 x buffered 117649 byte readinto bytearray:
      robust mean: 1.29 ms +/- 1.63 ms
      min: 18 µs

基准测试代码:

from _utils import BenchmarkResults

from timeit import timeit, repeat
import gc
import os
from contextlib import suppress
from math import floor
from random import randint

### Configuration

FILE_NAME = 'test.bin'
r = 5000
n = 100

reps = 1

chunk_sizes = list(range(7)) + [7**x for x in range(1,7)]

results = BenchmarkResults(description = 'Non-cachable binary data ingestion')


### Setup

FILE_SIZE = int(100e6)

# remove left over test file
with suppress(FileNotFoundError):
    os.unlink(FILE_NAME)

# determine how large a file needs to be to not fit in memory
gc.collect()
try:
    while True:
        data = bytearray(FILE_SIZE)
        del data
        FILE_SIZE *= 2
        gc.collect()
except MemoryError:
    FILE_SIZE *= 2
    print('Using file with {} GB'.format(FILE_SIZE / 1024**3))

# check enough data in file
required_size = sum(chunk_sizes)*2*2*reps*r
print('File size used: {} GB'.format(required_size / 1024**3))
assert required_size <= FILE_SIZE


# create test file
with open(FILE_NAME, 'wb') as file:
    buffer_size = int(10e6)
    data = bytearray(buffer_size)
    for i in range(int(FILE_SIZE / buffer_size)):
        file.write(data)

# read file once to try to force it into system cache as much as possible
from io import DEFAULT_BUFFER_SIZE
buffer_size = 10*DEFAULT_BUFFER_SIZE
buffer = bytearray(buffer_size)
with open(FILE_NAME, 'rb') as file:
    bytes_read = True
    while bytes_read:
        bytes_read = file.readinto(buffer)
    blk_size = file.raw._blksize

results.description += ' (file object blk_size = {})'.format(blk_size)

file = open(FILE_NAME, 'rb')

### Benchmarks

setup = \
"""
# random seek to avoid advantageous starting position biasing results
file.seek(randint(0, file.raw._blksize), 1)
"""

read_read = \
"""
file.read(chunk_size)
file.read(chunk_size)
"""

seek_seek = \
"""
file.seek(buffer_size, 1)
file.seek(buffer_size, 1)
"""

seek_read = \
"""
file.seek(buffer_size, 1)
file.read(chunk_size)
"""

read_read_timings = {}
seek_seek_timings = {}
seek_read_timings = {}
for chunk_size in chunk_sizes:
    read_read_timings[chunk_size] = []
    seek_seek_timings[chunk_size] = []
    seek_read_timings[chunk_size] = []

for j in range(r):
    #file.seek(0)
    for chunk_size in chunk_sizes:
        buffer = bytearray(chunk_size)
        read_read_timings[chunk_size].append(timeit(read_read, setup, number=reps, globals=globals()))
        #seek_seek_timings[chunk_size].append(timeit(seek_seek, setup, number=reps, globals=globals()))
        seek_read_timings[chunk_size].append(timeit(seek_read, setup, number=reps, globals=globals()))

for chunk_size in chunk_sizes:
    results['2 x buffered {} byte readinto bytearray'.format(chunk_size)] = read_read_timings[chunk_size]
    #results['2 x buffered {} byte seek'.format(chunk_size)] = seek_seek_timings[chunk_size]
    results['Buffered {} byte seek followed by {} byte readinto'.format(chunk_size, chunk_size)] = seek_read_timings[chunk_size]


### Cleanup
file.close()
os.unlink(FILE_NAME)

results.show()
results.save()

2020年2月24日编辑:

@finefoot 请求_utils包能够运行上面的代码。

from collections import OrderedDict
from math import ceil
from statistics import mean, stdev
from contextlib import suppress
import os
import inspect

class BenchmarkResults(OrderedDict):
    def __init__(self, *args, description='Benchmark Description', **kwArgs):
        self.description = description
        return super(BenchmarkResults, self).__init__(*args, **kwArgs)

    def __repr__(self):
        """Shows the results for the benchmarks in order of ascending duration"""
        characteristic_durations = []
        for name, timings in self.items():
            try:
                characteristic_durations.append(_robust_stats(timings)[0])
            except ValueError:
                if len(timings) > 1:
                    characteristic_durations.append(mean(timings))
                else:
                    characteristic_durations.append(timings[0])
        indx = _argsort(characteristic_durations)
        repr = '{}:\n'.format(self.description)
        items = list(self.items())
        for i in indx:
            name, timings = items[i]
            repr += '- {}:\n'.format(name)
            try:
                stats = _robust_stats(timings)
                repr += '      robust mean: {} +/- {}\n'.format(_units(stats[0]), _units(stats[1]))
            except ValueError:
                repr += '      timings: {}\n'.format(', '.join(map(_units, timings)))
            if len(timings) > 1:
                repr += '      min: {}\n'.format(_units(min(timings)))
        return repr

    def show(self):
        print(self)

    def save(self):
        caller = inspect.stack()[1]
        filename = os.path.splitext(caller.filename)[0] + '.log'
        with open(filename, 'w') as logfile:
            logfile.write(repr(self))


def _units(seconds, significant_figures=3):
    fmt = '{:.%sg} {}' % significant_figures
    if seconds > 1:
        return fmt.format(seconds, 's')
    elif seconds > 1e-3:
        return fmt.format(seconds*1e3, 'ms')
    elif seconds > 1e-6:
        return fmt.format(seconds*1e6, 'µs')
    elif seconds < 1e-6:
        return fmt.format(seconds*1e9, 'ns')
    elif seconds > 60:
        return fmt.format(seconds/60, 'min')
    else:
        return fmt.format(seconds/3600, 'hrs')
    raise ValueError()

def _robust_stats(timings, fraction_to_use=0.8):
    if len(timings) < 5:
        raise ValueError('To calculate a robust mean, you need at least 5 timing results')
    elts_to_prune = int(len(timings) * (1 - fraction_to_use))
    # prune at least the highest and the lowest result
    elts_to_prune = elts_to_prune if elts_to_prune > 2 else 2
    # round to even number --> symmetic pruning
    offset = ceil(elts_to_prune / 2)

    # sort the timings
    timings.sort()
    # prune the required fraction of the elements
    timings = timings[offset:-offset]
    return mean(timings), stdev(timings)

def _argsort(seq):
    # http://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python
    return sorted(range(len(seq)), key=seq.__getitem__)

if __name__ == '__main__':
    pass

我能够用您的代码重现该问题。但是,我注意到以下内容:您能否验证如果更换则问题会消失

file.seek(randint(0, file.raw._blksize), 1)

with

file.seek(randint(0, file.raw._blksize), 0)

in setup?我认为在读取 1 个字节的过程中,您可能会在某个时刻耗尽数据。读取 2 个字节、3 个字节等不会有任何数据可读取,因此速度要快得多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么从文件中读取 1 个字节比读取 2、3、4、... 字节慢 20 倍? 的相关文章

  • 使用 openCV 对图像中的子图像进行通用检测

    免责声明 我是计算机视觉菜鸟 我看过很多关于如何在较大图像中查找特定子图像的堆栈溢出帖子 我的用例有点不同 因为我不希望它是具体的 而且我不确定如何做到这一点 如果可能的话 但我感觉应该如此 我有大量图像数据集 有时 其中一些图像是数据集的
  • 如何打印没有类型的defaultdict变量?

    在下面的代码中 from collections import defaultdict confusion proba dict defaultdict float for i in xrange 10 confusion proba di
  • 如何在 Sublime Text 2 的 OSX 终端中显示构建结果

    我刚刚从 TextMate 切换到 Sublime Text 2 我非常喜欢它 让我困扰的一件事是默认的构建结果显示在 ST2 的底部 我的程序产生一些很长的结果 显示它的理想方式 如在 TM2 中 是并排查看它们 如何在 Mac 操作系统
  • 更改自动插入 tkinter 小部件的文本颜色

    我有一个文本框小部件 其中插入了三条消息 一条是开始消息 一条是结束消息 一条是在 单位 被摧毁时发出警报的消息 我希望开始和结束消息是黑色的 但被毁坏的消息 参见我在代码中评论的位置 插入小部件时颜色为红色 我不太确定如何去做这件事 我看
  • SQL Alchemy 中的 NULL 安全不等式比较?

    目前 我知道如何表达 NULL 安全的唯一方法 SQL Alchemy 中的比较 其中与 NULL 条目的比较计算结果为 True 而不是 NULL 是 or field None field value 有没有办法在 SQL Alchem
  • 安装后 Anaconda 提示损坏

    我刚刚安装张量流GPU创建单独的后环境按照以下指示here https github com antoniosehk keras tensorflow windows installation 但是 安装后当我关闭提示窗口并打开新航站楼弹出
  • 在循环中每次迭代开始时将变量重新分配给原始值(在循环之前定义)

    在Python中 你使用 在每次迭代开始时将变量重新分配给原始值 在循环之前定义 时 也就是说 original 1D o o o for i in range 0 3 new original 1D revert back to orig
  • 从列表中的数据框列中搜索部分字符串匹配 - Pandas - Python

    我有一个清单 things A1 B2 C3 我有一个 pandas 数据框 其中有一列包含用分号分隔的值 某些行将包含与上面列表中的一项的匹配 它不会是完美的匹配 因为它在其中包含字符串的其他部分 该列 例如 该列中的一行可能有 哇 这里
  • Python:字符串不会转换为浮点数[重复]

    这个问题在这里已经有答案了 我几个小时前写了这个程序 while True print What would you like me to double line raw input gt if line done break else f
  • 当玩家触摸屏幕一侧时,如何让 pygame 发出警告?

    我使用 pygame 创建了一个游戏 当玩家触摸屏幕一侧时 我想让 pygame 给出类似 你不能触摸屏幕两侧 的错误 我尝试在互联网上搜索 但没有找到任何好的结果 我想过在屏幕外添加一个方块 当玩家触摸该方块时 它会发出警告 但这花了很长
  • Numpy 优化

    我有一个根据条件分配值的函数 我的数据集大小通常在 30 50k 范围内 我不确定这是否是使用 numpy 的正确方法 但是当数字超过 5k 时 它会变得非常慢 有没有更好的方法让它更快 import numpy as np N 5000
  • 如何在 Django 中使用并发进程记录到单个文件而不使用独占锁

    给定一个在多个服务器上同时执行的 Django 应用程序 该应用程序如何记录到单个共享日志文件 在网络共享中 而不保持该文件以独占模式永久打开 当您想要利用日志流时 这种情况适用于 Windows Azure 网站上托管的 Django 应
  • 设置 torch.gather(...) 调用的结果

    我有一个形状为 n x m 的 2D pytorch 张量 我想使用索引列表来索引第二个维度 可以使用 torch gather 完成 然后然后还设置新值到索引的结果 Example data torch tensor 0 1 2 3 4
  • VSCode:调试配置中的 Python 路径无效

    对 Python 和 VSCode 以及 stackoverflow 非常陌生 直到最近 我已经使用了大约 3 个月 一切都很好 当尝试在调试器中运行任何基本的 Python 程序时 弹出窗口The Python path in your
  • 如何从没有结尾的管道中读取 python 中的 stdin

    当管道来自 打开 时 不知道正确的名称 我无法从 python 中的标准输入或管道读取数据 文件 我有作为例子管道测试 py import sys import time k 0 try for line in sys stdin k k
  • glpk.LPX 向后兼容性?

    较新版本的glpk没有LPXapi 旧包需要它 我如何使用旧包 例如COBRA http opencobra sourceforge net openCOBRA Welcome html 与较新版本的glpk 注意COBRA适用于 MATL
  • JavaFX ImageView 未更新

    因此 我尝试将图像加载并保存到 imageView 中 其中图像的位置是通过文件浏览器选择的 我已经为此工作好几天了 如果我不能解决这个问题 我就会中风 我已经尝试了我能想到的一切 预先感谢您的帮助 UPDATED 这是我的主要课程 pub
  • 协方差矩阵的对角元素不是 1 pandas/numpy

    我有以下数据框 A B 0 1 5 1 2 6 2 3 7 3 4 8 我想计算协方差 a df iloc 0 values b df iloc 1 values 使用 numpy 作为 cov numpy cov a b I get ar
  • Python - 字典和列表相交

    给定以下数据结构 找出这两种数据结构共有的交集键的最有效方法是什么 dict1 2A 3A 4B list1 2A 4B Expected output 2A 4B 如果这也能产生更快的输出 我可以将列表 不是 dict1 组织到任何其他数
  • Python 分析:“‘select.poll’对象的‘poll’方法”是什么?

    我已经使用 python 分析了我的 python 代码cProfile模块并得到以下结果 ncalls tottime percall cumtime percall filename lineno function 13937860 9

随机推荐

  • Webmatrix 布局——插入头部?

    我使用 Asp Net 和 Razor 视图引擎创建了一个网站 与使用 WebMatrix 相同 到目前为止 我一直在使用 SQL 直接查询数据库 但现在我有一个页面需要查询返回 XML 的 WCF 服务 让它返回 JSON 或 ODATA
  • 在 SQLAlchemy 中使用 declarative_base 时,如何根据需要绑定引擎?

    这是我的代码 from sqlalchemy import create engine Column Integer from sqlalchemy ext declarative import declarative base from
  • 如何在 postgresql 中找到列中的最大值?

    例如 name weight jon 100 jane 120 joe 130 如何只返回权重最大的人的名字 SELECT name FROM tbl ORDER BY weight DESC LIMIT 1 比其他答案性能更高 并且仅产生
  • 2013 年我应该使用 HTML5 编写我的网站吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 验证日期模式

    我需要一个 javascript 方法来验证日期模式 如下所示 2012 年 1 月 14 日 到目前为止 我不确定该模式使用哪个正则表达式 因为它不是标准日期 例如 14 01 2012 或 01 14 2012 或 01 04 2012
  • 为什么 jqueryUI datepicker 会抛出错误?

    我正在尝试 jqueryUI 但 firebug 在该脚本上捕获以下错误 function date datepicker 萤火虫错误如下 date datepicker is not a function 在我的 html 上 日期 id
  • 启发式和元启发式有什么区别?

    经过对算法的一些研究后 我发现了两个令我困惑的术语 我读过至少 20 篇论文 但都没有任何明确的定义 我希望有人能帮助我区分启发式算法和元启发式算法之间的区别 如果可能的话 添加它的来源 ps 我已经知道这些词的含义 但我不知道它们在计算机
  • 如何将旋转器数据从一个活动传递到另一个活动?

    此代码不会从微调器读取值 它始终只读取第一个值 btnResult setOnClickListener new View OnClickListener final String USN spnConversions getSelecte
  • 在 Visual Studio 中设置 FILE_ATTRIBUTE_DEVICE

    我想知道是否可以在 Visual C 中调用 CreateFile 函数来创建属性为 FILE ATTRIBUTE DEVICE 0x00000040 十六进制 64 十进制 的文件 根据 MSDN API FILE ATTRIBUTE D
  • Laravel 4 - 使用 hasMany 关系时插入多条记录

    仍在适应 Laravel 4 我有点不确定为什么这不起作用 在 L3 中 我能够将多条记录插入到表中 如下所示 comments array array message gt A new comment array message gt A
  • 依赖项规范必须是字符串或映射

    pubspec yaml 第 32 行第 5 列出错 依赖项规范必须是字符串或映射 32 assets 33 酒吧失败 65 问题是我的资产文件夹位于错误的位置 它不应该处于依赖关系下 另外 assets 前必须加2个空格 如图
  • Swift 中的属性和变量有什​​么区别?

    从一些最初的教程中 我看到属性属于一个类 本质上是 C 世界中使用的 全局变量 几年前编码 我还认为变量更多的是仅在方法中使用 存储信息的 本地 实体 然后我看到了 Quora 的这个帖子 https www quora com Apple
  • Java win32 库/api

    是否有合适的 Java win32 库 例如 显示当前进程 查找进程占用的端口号等 或者像 WMI 库之类的东西 看一下JNA https github com twall jna 这是与本机代码通信的 100 纯 java 方式 他们有一
  • 如何抑制 Delphi DataSnap 错误消息对话框?

    我们在 Windows 2003 Server 上运行 DataSnap Delphi 2009 应用程序 DataSnap 客户端和服务器位于同一台计算机上 通过 Borland Socketserver 使用 DCOM 客户端运行后台批
  • 为什么将 Avro 与 Kafka 结合使用 - 如何处理 POJO

    我有一个 Spring 应用程序 它是我的 kafka 生产者 我想知道为什么 avro 是最好的选择 我读到了它以及它提供的所有内容 但为什么我不能序列化我用 jackson 自己创建的 POJO 并将其发送到 kafka 我这样说是因为
  • Amazon MWS Feed API 更新订单状态时出现问题

    我正在使用 amazon mws feed api 来更新我网站上的订单状态 当我打电话给提交供稿api 提交成功 但是 当我打电话给获取Feed提交结果 它返回给我一个错误 指出
  • 使用 UITextView 和 NSMutableAttributedString 对齐文本

    我正在尝试为一个合理的文本UITextView with NSMutableAttributedString the NSMutableAttributedString是由不同的NSAttributedString因为我需要粗体和常规字体
  • 什么是 Chocolatey“安装”包?

    关于审查巧克力包装 https chocolatey org packages可用时 我遇到了一些有两个 或有时更多 显然用于同一产品的软件包 乍一看无法区分 例如 有自动热键包 然后还有一个自动热键 install 在这里查看 Choco
  • 为什么 JavaScript 中 (([]===[])+/-/)[1] = 'a' 和 (1+{})[(1<<1)+1] = 'b' ?

    最近我发现了一个有趣的网站 其中展示了 Javascript 混淆器 http bl ocks org jasonsperske 5400283 http bl ocks org jasonsperske 5400283 例如 1 give
  • 为什么从文件中读取 1 个字节比读取 2、3、4、... 字节慢 20 倍?

    我一直试图理解之间的权衡read and seek 对于小的 跳跃 读取不需要的数据比使用跳过它更快seek 在计时不同的读取 查找块大小以找到临界点时 我遇到了一个奇怪的现象 read 1 大约慢20倍read 2 read 3 等 对于