为什么比较匹配的字符串比比较不匹配的字符串更快? [复制]

2024-05-07

这里有两个测量值:

timeit.timeit('"toto"=="1234"', number=100000000)
1.8320042459999968
timeit.timeit('"toto"=="toto"', number=100000000)
1.4517491540000265

正如您所看到的,比较两个匹配的字符串比比较两个大小相同但不匹配的字符串要快。 这是相当令人不安的:在字符串比较期间,我相信Python正在逐个字符地测试字符串,所以"toto"=="toto"测试时间应该比"toto"=="1234"因为它需要对一项进行四次测试才能进行不匹配的比较。也许比较是基于哈希的,但在这种情况下,两次比较的时间应该相同。

Why?


结合我的评论和@khelwood 的评论:

TL;DR:
在分析两次比较的字节码时,它揭示了'time' and 'time'字符串被分配给同一个对象。因此,预先身份检查(在 C 级)是比较速度提高的原因。

相同对象分配的原因是,作为实施细节,CPython 实习生字符串仅包含“名称字符”(即字母和下划线字符)。这可以实现对象的身份检查。


字节码:

import dis

In [24]: dis.dis("'time'=='time'")
  1           0 LOAD_CONST               0 ('time')  # <-- same object (0)
              2 LOAD_CONST               0 ('time')  # <-- same object (0)
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

In [25]: dis.dis("'time'=='1234'")
  1           0 LOAD_CONST               0 ('time')  # <-- different object (0)
              2 LOAD_CONST               1 ('1234')  # <-- different object (1)
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

作业时间:

在使用分配进行时间测试时也可以看到“加速”。将两个变量分配(和比较)到同一字符串比将两个变量分配(和比较)到不同字符串要快。底层逻辑正在执行对象比较,进一步支持这一假设。这将在下一节中得到证实。

In [26]: timeit.timeit("x='time'; y='time'; x==y", number=1000000)
Out[26]: 0.0745926329982467

In [27]: timeit.timeit("x='time'; y='1234'; x==y", number=1000000)
Out[27]: 0.10328884399496019

Python源代码:

正如 @mkrieger1 和 @Masklinn 在他们的评论中所提供的,源代码 https://github.com/python/cpython/blob/main/Objects/unicodeobject.c#L11134 for unicodeobject.c首先执行指针比较,如果True,立即返回。

int
_PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
    assert(PyUnicode_CheckExact(str1));
    assert(PyUnicode_CheckExact(str2));
    if (str1 == str2) {                  // <-- Here
        return 1;
    }
    if (PyUnicode_READY(str1) || PyUnicode_READY(str2)) {
        return -1;
    }
    return unicode_compare_eq(str1, str2);
}

附录:

  • 参考答案 https://stackoverflow.com/a/47529318/6340496很好地说明了如何读取反汇编的字节码输出。由@Delgan 提供
  • 参考答案 https://stackoverflow.com/a/42685254/6340496它很好地描述了 CPython 的字符串驻留。由@ShadowRanger 提供
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么比较匹配的字符串比比较不匹配的字符串更快? [复制] 的相关文章

随机推荐

  • perl生成字符串来匹配正则表达式

    我尝试找到一种方法来生成与正则表达式匹配的字符串 例如以下正则表达式 A Z 6 6 A Z2 9 A NP Z0 9 A Z0 9 3 3 0 1 我尝试过 Cpan 上的一些 perl 模块不起作用 gt 字符串 随机 gt 正则表达式
  • 通过cas进行ajax调用

    我需要编写一个谷歌小工具来读取谷歌群组的提要 问题是我正在进行 ajax 调用来检索提要 而我们的 google apps 域受 CAS 中央身份验证服务 保护 因此 我在拨打电话时收到 400 错误请求 我怀疑浏览器在进行 ajax 调用
  • 将字体导入 React 应用程序

    我正在尝试在我的应用程序中使用 Roboto 字体 但遇到了困难 I did npm install save typeface roboto并添加了import typeface roboto 到我的 React 组件 但仍然无法改变我的
  • 使用 AlamofireImage 下载图像有进度吗?

    有没有办法使用 AlamofireImage 下载图像并获得有关下载进度的某种反馈 同时利用它的强大功能UIImage 扩展 图像过滤器和图像缓存 我知道我可以退回到平原Alamofire request responseImage但我想让
  • 尝试通过 knex 连接到 Mssql 服务器

    我正在尝试使用 knex 连接到远程数据库 但收到此错误 乏味已弃用默认值options encrypt将会改变自false to true 请通过false如果您想保留当前行为 请明确地表示 在node modules mssql lib
  • 带有 Viper 和 Vimpulse 的 Emacs 缺少哪些 Vim 功能?

    Emacs 的一些重要功能在 Vim 中是缺失的 例如 comint 模式 并且没有脚本 插件可以替代它们 与 Emacs 相比 Vim 也有一些优点 例如模式编辑和通常更好的默认快捷键 然而 Viper 模式让我两者兼而有之 Vimpul
  • 如何修改s_client的代码?

    我正在玩apps s client c in the openssl源代码 我想进行一些更改并运行它 但是在保存文件并执行操作后 我的更改没有得到反映make all or a make 例如 我改变了sc usage函数为此 BIO pr
  • 请求开发者证书的分发配置文件

    使用 Xcode 9 1 构建 iOS 应用程序后 我尝试将其存档 但我收到以下错误消息 配置文件 MyAppProfile 不包括签名证书 iPhone Developer My Name X1YZ2AB3CD 仔细观察后 我发现 MyA
  • 如何使用 PHP 跳过 XML 文件中的无效字符

    我正在尝试使用 PHP 解析 XML 文件 但收到错误消息 解析器错误 字符 0x0 超出允许范围 我认为这是因为 XML 的内容 我认为有一个特殊符号 我能做些什么来修复它 我还得到 解析器错误 标签项行中数据过早结束 可能是什么原因导致
  • 没有找到适合 jdbc.sqlite 的驱动程序

    所以首先我之前看到过这个问题 我查看了以前的答案并尝试用它来解决我的问题 但是我做不到 我正在创建一个图书馆系统 并为注册类和登录类编写了代码 并为数据库创建了一个类 当我尝试运行该程序时 我收到一条消息 指出没有找到合适的驱动程序 后跟数
  • 如何以编程方式在 Genymotion 上刷新 zip

    我正在尝试将谷歌应用程序刷新到 genymotion 模拟器中 我可以使用拖放功能来完成此操作 但我的项目需要 google apps zip 已加载到 genymotion 机器中并且在内部闪烁 以避免与桌面交互 我检查过类似的问题thi
  • HTTP 查询字符串和 []

    PHP 使用 在查询参数名称中 以确保多次出现的参数都出现在 GET超全局变量 否则只出现最后一次出现的情况 还有其他软件可以做到这一点吗 但从RFC 3986 https www rfc editor org rfc rfc3986 以及
  • Raspberry Pi 无延迟(<10ms)视频流

    我正在基于 Raspberry Pi 构建四轴飞行器 我想通过蜂窝连接将网络摄像头的视频流式传输到我的计算机 我尝试了 ffmpeg 和 mjpg 但它必须有很大的延迟才能仅通过观看视频来控制 Quad 我的问题是是否可以以非常小的延迟 如
  • 将 Sprockets 的“depend_on”指令指向非资产文件

    我有一个app assets javascripts moufa js erb填充来自 a 的值的文件config moufa yml文件 我想使用depend onsprockets 指令 以便每次 yaml 文件发生更改时 它都会重新编
  • 如何画一个中间透明的圆

    我试图用以下代码绘制一个白色圆圈 mPaint setColor 0xFFFFFFFF canvas drawCircle x y radius mPaint 但它显示为固态磁盘 如何让它只显示为中心透明的圆形轮廓 我查看了帮助 这对我来说
  • Android Studio .2.2 和 Gradle 包不存在

    Android Studio 和导入外部 Java 库的新功能 我已阅读有关配置 Gradle 依赖项的帖子 并修复了我的第一个包不存在错误 这些是我的 MainAcitivity java 文件中的导入语句 import com goog
  • 在 python 中读取具有恶意字节 0xc0 的文件,导致 utf-8 和 ascii 出错

    尝试将制表符分隔的文件读入 pandas 数据帧 gt gt gt df pd read table fn na filter False error bad lines False 它会出错 如下所示 b Skipping line 58
  • 如何使用 rel=preload 预加载材质图标?

    我正在尝试使用谷歌灯塔优化我的网页 该报告指出 在导入 Material Design 图标的链接上使用 rel preloads 我尝试使用语法预加载它们 我也尝试过使用字体进行预加载 类型为 woff woff2 和 ttf 它们似乎都
  • 解释R中模型多重共线性的别名表测试

    有人可以帮助我解释别名函数输出 以测试多元回归模型中的多重共线性 我知道我的模型中的一些预测变量是高度相关的 我想使用别名表来识别它们 Model Score Comments Pros Cons Advice Response Value
  • 为什么比较匹配的字符串比比较不匹配的字符串更快? [复制]

    这个问题在这里已经有答案了 这里有两个测量值 timeit timeit toto 1234 number 100000000 1 8320042459999968 timeit timeit toto toto number 100000