当前位置: 首页 > 知识库问答 >
问题:

为什么字符串的启动速度比in慢?

闻人越
2023-03-14

令人惊讶的是,我发现startswith比中的慢:

In [10]: s="ABCD"*10

In [11]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 307 ns per loop

In [12]: %timeit "XYZ" in s
10000000 loops, best of 3: 81.7 ns per loop

众所周知,操作中的需要搜索整个字符串,startswith只需要检查前几个字符,所以startswith应该更高效。

s足够大时,启动s的速度更快:

In [13]: s="ABCD"*200

In [14]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 306 ns per loop

In [15]: %timeit "XYZ" in s
1000000 loops, best of 3: 666 ns per loop

因此,调用startswith似乎有一些开销,这使得当字符串很小时,调用速度会变慢。

然后我试图弄清楚startswith调用的开销是多少。

首先,我使用了一个f变量来降低点操作的成本——正如这个答案中提到的——在这里我们可以看到startswith仍然较慢:

In [16]: f=s.startswith

In [17]: %timeit f("XYZ")
1000000 loops, best of 3: 270 ns per loop

此外,我测试了空函数调用的成本:

In [18]: def func(a): pass

In [19]: %timeit func("XYZ")
10000000 loops, best of 3: 106 ns per loop

无论点运算和函数调用的成本如何,启动时间约为(270-106)=164ns,但运行中仅需要81.7ns。似乎还有一些开销可以开始,那是什么?

按照poke和lvc的建议,在< code>startswith和< code>__contains__之间添加测试结果:

In [28]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 314 ns per loop

In [29]: %timeit s.__contains__("XYZ")
1000000 loops, best of 3: 192 ns per loop

共有2个答案

山煜祺
2023-03-14

这可能是因为<code>str。startswith()比str做得更多__contains_(),也因为我相信str__contains__完全在C中运行,而str。startswith()必须与Python类型交互。它的签名是<code>str。startswih(prefix[,start[,end]]),其中prefix可以是要尝试的字符串的元组。

张俊茂
2023-03-14

正如在注释中已经提到的,如果您使用< code > s . _ _ contains _ _(" XYZ ")您会得到一个更类似于< code>s.startswith("XYZ")的结果,因为它需要采取相同的途径:在字符串对象上进行成员查找,然后进行函数调用。这通常有点贵(当然还不够贵)。另一方面,当您在s中执行< code >“XYZ”时,解析器会解释该操作符,并可以简化对< code>__contains__的成员访问(或者说是其背后的实现,因为< code>__contains__本身只是访问实现的一种方式)。

您可以通过查看字节码来了解这一点:

>>> dis.dis('"XYZ" in s')
  1           0 LOAD_CONST               0 ('XYZ')
              3 LOAD_NAME                0 (s)
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE
>>> dis.dis('s.__contains__("XYZ")')
  1           0 LOAD_NAME                0 (s)
              3 LOAD_ATTR                1 (__contains__)
              6 LOAD_CONST               0 ('XYZ')
              9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             12 RETURN_VALUE

因此,将s.__contains__(“XYZ”)s.startswith(“XYZ”)进行比较会产生更相似的结果,但是对于示例字符串sstartswith仍然会更慢。

为此,您可以检查两者的实现。有趣的是,contains实现是静态类型的,并且假设参数本身是unicode对象。所以这是非常有效的。

然而,startswith实现是一个“动态”Python方法,需要实现来实际解析参数。startswith还支持元组作为参数,这使得该方法的整个启动有点慢:(由我缩短,带有我的评论):

static PyObject * unicode_startswith(PyObject *self, PyObject *args)
{
    // argument parsing
    PyObject *subobj;
    PyObject *substring;
    Py_ssize_t start = 0;
    Py_ssize_t end = PY_SSIZE_T_MAX;
    int result;
    if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
        return NULL;

    // tuple handling
    if (PyTuple_Check(subobj)) {}

    // unicode conversion
    substring = PyUnicode_FromObject(subobj);
    if (substring == NULL) {}

    // actual implementation
    result = tailmatch(self, substring, start, end, -1);
    Py_DECREF(substring);
    if (result == -1)
        return NULL;
    return PyBool_FromLong(result);
}

这可能是 startwith 对于包含的字符串较慢的一个重要原因,因为它很简单。

 类似资料:
  • 问题内容: 我有一个名为Memcached.Js的项目,它是Memcached服务器到Node.js的端口。 我一直在使用字符串和缓冲区进行比较,比较内存占用量和性能。对于内存,毫无疑问,缓冲区是正确的选择。 但令我惊讶的是,表演并非如此。执行字符串操作比使用缓冲区更快。这是我尝试的: 完整的代码在这里:https : //github.com/dalssoft/memcached.js/blob

  • 问题内容: 我有一个Android应用程序,我想检查安装的应用程序名称是否与传递给包含此代码的函数的字符串匹配。代码和示例如下: 假设您打过电话,并且手机上的应用程序名称与返回的名称相同。但是,它永远不会。我记录了结果,它应该匹配,但事实并非如此。任何人都可以请问我为什么这行不通吗? 问题答案: 使用String的equals()方法代替==运算符来比较字符串: 在Java中,新手遇到的最常见错误

  • 这里有2个测量: 正如您所见,比较两个匹配的字符串比比较两个大小相同但不匹配的字符串要快。这是非常令人不安的:在字符串比较期间,我认为python是逐字符测试字符串的,所以应该比更长,因为它需要对1进行4次测试才能进行不匹配的比较。可能比较是基于哈希的,但在这种情况下,两种比较的计时应该相同。 你知道为什么吗?

  • 问题内容: 今天,我做了一些快速基准测试来测试and的速度性能: 结果如下: 为什么运行速度差异如此之大? 基准系统: 问题答案: 从这个Oracle博客中: 使用GetSystemTimeAsFileTime方法实现该方法,该方法本质上只是读取Windows维护的低分辨率日期时间值。读取此全局变量自然非常快- 根据报告的信息,大约需要6个周期。 使用 (如果可用,则返回。)实现,具体取决于运行的

  • 问题内容: 使用以下代码时,我们的代码需要10分钟才能虹吸68,000条记录: 但是,当我们执行以下操作时,仅需1秒钟: 这是代码: 我曾经用python编写过的所有代码都使用第一个选项。这只是基本的字符串操作…我们正在从文件中读取输入,对其进行处理并将其输出到新文件中。我100%确信第一种方法的运行时间比第二种方法长约600倍,但是为什么呢? 正在处理的文件是csv,但使用〜而不是逗号。我们在这

  • 问题内容: 我从书中看到以下代码: 但没有提到为什么“一个”大于“四个”。我试过了,它小于a和b。我想知道JavaScript如何比较这些字符串。 问题答案: 因为和许多编程语言一样,字符串是按字典顺序进行比较的。 你可以认为这是一个空想家版本的字母顺序,区别在于字母排序仅覆盖了26个字符通过。