如何查找Python代码中的类型转换 排查类型混用导致的性能瓶颈
NumPy类型与Python原生类型混用引发的性能问题
混用不同数据类型会导致程序运行速度大幅下降,典型场景是numpy.int系列类型与Python通用原生int类型混用,部分场景下可造成高达20倍的性能损耗。
import numpy import random from timeit import timeit N = 10000 python_ints_in = [random.randint(50, 100) for _ in range(N)] python_ints_out = [random.randint(50, 100) for _ in range(N)] numpy_ints_out = numpy.array(python_ints_out, dtype=numpy.intc) test_set = set(python_ints_in) def pyt(): return sum(i in test_set for i in python_ints_out) def num(): return sum(i in test_set for i in numpy_ints_out) print(timeit(pyt, number=1000)) # 0.45s print(timeit(num, number=1000)) # 11.3s
我需要在大型项目中追踪这类隐式类型处理逻辑,验证是否可以通过统一数据类型进一步提升性能。
性能剖析进展
我已经完成了基础性能剖析工作,上述问题就是通过剖析发现的。这类问题不一定是代码里显式写出来的类型转换,但都和类型匹配、类型处理逻辑直接相关,类型混用是已经确认的明确性能瓶颈。
上文的set成员判断是我复现该瓶颈写的最小可复现示例,实际项目中同类性能问题还出现在dict键值操作、算术运算等各类场景中,都是后续需要追踪排查的对象。目前我已经通过性能剖析定位修复了几处核心问题点,修复后程序整体运行耗时降低了一半,但剩余的10%性能损耗仍然无法接受。
算术运算场景的性能测试
import numpy import dis from timeit import timeit a_int = 123 b_int = 178 a_intc = numpy.intc(a_int) b_intc = numpy.intc(b_int) print(type(b_intc)) # <class 'numpy.int32'> print(type(b_int)) # <class 'int'> def pyt(): return a_int//b_int def mix(): return a_int//b_intc def num(): return a_intc//b_intc print(timeit(pyt, number=1000000)) # 0.056 print(timeit(mix, number=1000000)) # 1.382 print(timeit(num, number=1000000)) # 0.101
对三个函数反汇编后可以看到,三者的字节码逻辑完全一致,仅加载的操作数类型存在区别:
# pyt:纯Python原生int运算 14 0 LOAD_GLOBAL 0 (a_int) 2 LOAD_GLOBAL 1 (b_int) 4 BINARY_FLOOR_DIVIDE 6 RETURN_VALUE # mix:Python原生int与NumPy int混合运算 17 0 LOAD_GLOBAL 0 (a_int) 2 LOAD_GLOBAL 1 (b_intc) 4 BINARY_FLOOR_DIVIDE 6 RETURN_VALUE # num:纯NumPy int运算 20 0 LOAD_GLOBAL 0 (a_intc) 2 LOAD_GLOBAL 1 (b_intc) 4 BINARY_FLOOR_DIVIDE 6 RETURN_VALUE
内容的提问来源于stack exchange,提问作者Askold Ilvento
相关产品推荐
相关产品推荐

