首页 > 解决方案 > 为什么 Python 中的 traceback.extract_stack() 这么慢?

问题描述

在测试期间,我发现调用traceback.extract_stack()非常慢。获取堆栈跟踪的价格与执行数据库查询相当。

我想知道我是否做错了什么或错过了什么。令我惊讶的是,我认为调用extract_stack()是 Python 中的内部调用,它是在内存中的运行时执行的,如果不是即时的,应该是超快的。相比之下调用数据库查询涉及外部服务(网络通信)等。

示例代码如下。您可以尝试在 20.000 次迭代中检索回溯需要多长时间,以及从堆栈跟踪中检索前几项的速度有多快 - 将limit=None参数设置为其他值。

我的测试在各种系统/配置上显示了各种结果,但都有一个共同点,即调用堆栈跟踪并不便宜几个数量级,它与调用 SQL insert 几乎相同

           20k SQL inserts | 20k stack traces
Win                5.4 sec           14.4 sec
FreeBSD            5.0 sec            3.7 sec
Ubuntu GCP        16.6 sec            2.4 sec

Windows:笔记本电脑、本地 SSD。FreeBSD:服务器,本地 SSD。Ubuntu:谷歌云,共享 SSD。

我做错了什么还是有什么解释为什么 traceback.extract_stack() 这么慢?我可以以某种方式更快地检索堆栈跟踪吗?

示例代码。运行$ pip install pytest然后$ pytest -s -v

import datetime
import unittest
import traceback


class TestStackTrace(unittest.TestCase):

    def test_stack_trace(self):
        start_time = datetime.datetime.now()
        iterations = 20000
        for i in range(0, iterations):
            stack_list = traceback.extract_stack(limit=None)  # set 0, 1, 2...
            stack_len = len(stack_list)
            self.assertEqual(1, 1)
        finish_time = datetime.datetime.now()
        print('\nStack length: {}, iterations: {}'.format(stack_len, iterations))
        print('Trace elapsed time: {}'.format(finish_time - start_time))

您不需要它,但如果您想与 SQL 插入进行比较,就在这里。只需将它作为第二个测试方法插入到 TestStackTrace 类中。运行CREATE DATABASE pytest1;CREATE TABLE "test_table1" (num_value BIGINT, str_value VARCHAR(10));

def test_sql_query(self):
    start_time = datetime.datetime.now()
    con_str = "host='127.0.0.1' port=5432 user='postgres' password='postgres' dbname='pytest1'"
    con = psycopg2.connect(con_str)
    con.autocommit = True
    con.set_session(isolation_level='READ COMMITTED')
    cur = con.cursor()
    for i in range(0, 20000):
        cur.execute('INSERT INTO test_table1 (num_value, str_value) VALUES (%s, %s) ', (i, i))
    finish_time = datetime.datetime.now()
    print('\nSQL elapsed time: {}'.format(finish_time - start_time))

标签: pythonstack-trace

解决方案


traceback.extract_stack()不是用C实现的Python中的内部调用。整个traceback模块都是用Python实现的,这也是它比较慢的原因。由于堆栈跟踪通常仅在调试期间需要,因此它的性能通常不是问题。如果您确实需要它的高性能版本,您可能必须自己将其重新实现为 C/C++ 扩展。


推荐阅读