为什么 Python 中的 traceback.extract_stack() 这么慢?
Why is traceback.extract_stack() in Python so slow?
在测试期间我发现调用 traceback.extract_stack()
非常慢。获取堆栈跟踪的价格与执行数据库查询的价格相当。
我想知道我是否做错了什么或遗漏了什么。令我惊讶的是,我认为调用 extract_stack()
是 Python 中的内部调用,它是在运行时在内存中执行的,即使不是即时的,也应该是超快的。相比之下调用数据库查询涉及到外部服务(网络通信)等
示例代码如下。您可以尝试在假设 20.000 次迭代中检索回溯需要多长时间,以及从堆栈跟踪中检索前几项的速度有多快 - 将 limit=None
参数设置为其他值。
我的测试在各种 systems/configurations 上显示了不同的结果,但它们的共同点是 调用堆栈跟踪并不便宜几个数量级,它几乎与调用 SQL 相同插入.
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:Google 云,共享 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 class。 运行 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))
traceback.extract_stack()
不是用C实现的Python中的内部调用,整个traceback
模块都是在Python中实现的,所以比较慢。由于堆栈跟踪通常只在调试期间需要,因此通常不关心其性能。如果您确实需要它的高性能版本,您可能需要自己将其重新实现为 C/C++ 扩展。
在测试期间我发现调用 traceback.extract_stack()
非常慢。获取堆栈跟踪的价格与执行数据库查询的价格相当。
我想知道我是否做错了什么或遗漏了什么。令我惊讶的是,我认为调用 extract_stack()
是 Python 中的内部调用,它是在运行时在内存中执行的,即使不是即时的,也应该是超快的。相比之下调用数据库查询涉及到外部服务(网络通信)等
示例代码如下。您可以尝试在假设 20.000 次迭代中检索回溯需要多长时间,以及从堆栈跟踪中检索前几项的速度有多快 - 将 limit=None
参数设置为其他值。
我的测试在各种 systems/configurations 上显示了不同的结果,但它们的共同点是 调用堆栈跟踪并不便宜几个数量级,它几乎与调用 SQL 相同插入.
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:Google 云,共享 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 class。 运行 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))
traceback.extract_stack()
不是用C实现的Python中的内部调用,整个traceback
模块都是在Python中实现的,所以比较慢。由于堆栈跟踪通常只在调试期间需要,因此通常不关心其性能。如果您确实需要它的高性能版本,您可能需要自己将其重新实现为 C/C++ 扩展。