Python比C++慢,尤其是循环时?探究Python与C++区别
目录

1。为什么Python这么慢?
Python比C ++慢,尤其是在有周期时,Python和C+之间的差异主要是:
1.1动态变量
C ++需要严格的变量类型的定义,例如INT或Float类型。但是Python不需要,它删除了可变语句和数据类型。 Python是一种动态类型的语言。它会根据变量进行操作时自动推断类型。这种动态类型的特征使Python的写作更加容易,灵活,但与此同时,它增加了一定的开销时间。 /c ++只是操作过程中简单的内存读取,写入和机器命令(加法,减法,乘法等),因此C/C ++的速度比Python快得多。
1.2。解释语言
C/C ++是一种编译语言。您需要首先将源代码编译到机器代码中,然后运行程序。
Python 是一种解释型语言。解释器直接解释了其源代码,这意味着在编写Python代码时,代码并不需要将代码编译到可执行文件中,但可以直接运行代码。因此,Python的执行速度比C/C ++慢得多。
解决此问题的一个解决方案是JIT(即时编译):JIT编译器将动态地将高级语言编写的代码转换为机器代码,该代码可以由计算机处理器直接执行。这正在运行。在执行代码之前,它称为“即时”。 JIT优化了特定硬件和操作系统的代码,这可以使Python代码显着改善。
2。介绍和使用numba
github主页:
在线文档:
可以直接pip/conda下载库
conda install numba
pip install numba
NUMBA非常适合使用Numpy数组,功能和循环代码。使用的方法是装饰器,使用它!节省很多时间来节省数十次。 Numba的可用范围:
2.1 numba加速python小例子
def cal_sum(a):
result = 0
for i in range(a.shape[0]):
for j in range(a.shape[1]):
result += a[i, j]
return result
start = time.perf_counter()
a = np.random.random((5000, 5000))
result = cal_sum(a)
end = time.perf_counter()
print("原始代码耗时:{}s".format((end - start)))
#OUT:
#原始代码耗时:5.725140199996531s
import numba
@numba.jit(nopython=True)
def cal_sum(a):
result = 0
for i in range(a.shape[0]):
for j in range(a.shape[1]):
result += a[i, j]
return result
start = time.perf_counter()
a = np.random.random((5000, 5000))
result = cal_sum(a)
end = time.perf_counter()
print("加速后耗时:{}s".format((end - start)))
#OUT:
#加速后耗时:0.2892118000017945s
@jit(notython = true)和@njit等效。此选项表示Numba在编译过程中避免了尽可能多地使用Python对象,并将Python代码转换为更快的机器代码,而不是使用Python Instryter执行代码。
Numba首次调用函数时编译,但是在编译发生后,Numba将缓存该函数的机器代码。如果再次调用该函数,则它将直接从缓存加载,而无需再次编译。简而言之,numba函数在代码中使用,第二和第三次...调用功能操作的时间少于第一次。
x = np.arange(100).reshape(10, 10)
@jit(nopython=True)
def go_fast(a):
trace = 0.0
for i in range(a.shape[0]):
trace += np.tanh(a[i, i])
return a + trace
start = time.perf_counter()
go_fast(x)
end = time.perf_counter()
print("首次调用耗时:{}s".format((end - start)))
start = time.perf_counter()
go_fast(x)
end = time.perf_counter()
print("再次调用耗时:{}s".format((end - start)))
#OUT:
#首次调用耗时:0.16958359999989625s
#再次调用耗时:4.7599998652003706e-05s
官方教学网站:
我使用了官方代码来比较未使用的平行并使用并行使用,但是平行较慢,没有谨慎的理由。
from numba import njit
@njit()
def prange_test(A):
s = 0
for i in range(A.shape[0]):
s += A[i]
return s
start = time.perf_counter()
a = np.arange(1000)
result = prange_test(a)
end = time.perf_counter()
print("无并行耗时:{}s".format((end - start)))
#OUT:
#无并行耗时:0.07213479999336414s
from numba import njit, prange
@njit(parallel=True)
def prange_test(A):
s = 0
# Without "parallel=True" in the jit-decorator
# the prange statement is equivalent to range
for i in prange(A.shape[0]):
s += A[i]
return s
start = time.perf_counter()
a = np.arange(1000)
result = prange_test(a)
end = time.perf_counter()
print("并行耗时:{}s".format((end - start)))
#OUT:
#并行耗时:0.36391139999614097s
2.2个人经验
以上功能相对简单,但是在实际使用中,我们的功能可能更复杂。只需将装饰器直接添加到功能中,就会有各种错误。我们需要调整问题的功能代码。问题和解决方案。
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Cannot infer the type of variable 'result', have imprecise type: list(undefined)<iv=None>.
For Numba to be able to compile a list, the list must have a known and
precise type that can be inferred from the other variables. Whilst sometimes
the type of empty lists can be inferred, this is not always the case, see this
documentation for help:
https://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-has-an-untyped-list-problem
一些错误会告诉您报告错误的原因。仔细单击它,然后根据含义的含义修改代码,但解决此问题的解决方案如下:
@numba.jit(nopython=True)
def test():
result, result1 = [], 0
return result, result1
test()
# 改为
@numba.jit(nopython=True)
def test():
result = []
result1 = 0
return result, result1
test()
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Unknown attribute 'tolist' of type array(float32, 1d, C)
...
Untyped global name 'input': Cannot determine Numba type of <class 'method'>
这种问题是因为Numba仍然具有一些不支持的函数,例如上面python随附的input()函数以及数组的tolist()函数。当遇到这些问题时,或自行重写功能。
def test_func():
return True
@jit(nopython=True)
def test():
flag = test_func()
test()
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'test_func': Cannot determine Numba type of <class 'function'>
这个问题是NUMBA不支持函数中嵌套函数的功能。解决方案是将呼叫函数合并到一个函数中。
将有一些与列表有关的错误。 Numba似乎不支持列表操作,尤其是类似于[[[1,2],[2,3]],[2,2],[8,33]]]的嵌套列表,该解决方案是将此列表更改为操作阵列。
2.3其他
Numba还提供了许多其他加速方法(我还没有尝试过):
参考:Python加快大型杀人装置的Numba文章