谁更快?Python pk C++,原来主角是Numba

2021-08-1509:29:25编程语言入门到精通Comments2,441 views字数 4130阅读模式

Python 是一个用途非常广泛的编程语言,拥有成千上万的第三方库,在人工智能、机器学习、自动化等方面有着广泛的应用,众所周知,Python 是动态语言,有全局解释器锁,比其他静态语言要慢,也正是这个原因,你也许会转向其他语言如 Java、C++,不过先等等,今天分享一个可以让 Python 比 C++ 还要快的技术,看完再决定要不要转吧。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

今天的主角就是 Numba,Numba 是一个开源的即时编译器(JIT compiler),可将 Python 和 NumPy 的代码的转换为快速的机器码,从而提升运行速度。可以达到 C 或 FORTRAN 的速度。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

这么牛逼是不是很难用呢?No,No,No,So easy,你不需要替换 Python 解释器,不需要单独编译,甚至不需要安装 C / C ++ 编译器。只需将 Numba 提供的装饰器放在 Python 函数上面就行,剩下的就交给 Numba 完成。举个简单的例子:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

from numba import jit
import random

@jit(nopython=True)
def monte_carlo_pi(nsamples):
    acc = 0
    for i in range(nsamples):
        x = ()
        y = ()
        if (x ** 2 + y ** 2) < :
            acc += 1
    return  * acc / nsamples

Numba 是专为科学计算而设计的,在与 NumPy 一起使用时,Numba 会为不同的数组数据类型生成专门的代码,以优化性能:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

@(nopython=True, parallel=True)
def logistic_regression(Y, X, w, iterations):
    for i in range(iterations):
        w -= ((( /
              ( + (-Y * (X, w)))
              - ) * Y), X)
    return w

现在我们来看看,同样的代码,使用 Numba 前后与 C++ 的性能对比。比如说我们要找出 1000 万以内所有的素数,代码的算法逻辑是相同的:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

Python 代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

import math
import time

def is_prime(num):
    if num == 2:
        return True
    if num <= 1 or not num % 2:
        return False
    for div in range(3, int((num) + 1), 2):
        if not num % div:
            return False
    return True

def run_program(N):
    total = 0
    for i in range(N):
        if is_prime(i):
            total += 1
    return total


if __name__ == "__main__":
    N = 10000000
    start = ()
    total = run_program(N)
    end = ()
    print(f"total prime num is {total}")
    print(f"cost {end - start}s")

执行耗时:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

total prime num is 664579
cost 47.386465072631836s

C++ 代码如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

#include 
#include 
#include 
using namespace std;


bool isPrime(int num) {

    if (num == 2) return true;
    if (num <= 1 || num % 2 == 0) return false;
    double sqrt_num = sqrt(double(num));
    for (int div = 3; div <= sqrt_num; div +=2){
       if (num % div == 0) return false;
    }
     return true;
}

int run_program(int N){

    int total = 0;
    for (int i; i < N; i++) {
        if(isPrime(i)) total ++;
    }
    return total;
}

int main()
{
    int N = 10000000;
    clock_t start,end;
    start = clock();
    int total = run_program(N);
    end = clock();
    cout << "total prime num is " << total;
    cout << "\ncost " << (end - start) / ((double) CLOCKS_PER_SEC) << "s\n";
    return 0;
}
$ g++  -o isPrime
$ ./isPrime
total prime num is 664579
cost 6221s
谁更快?Python pk C++,原来主角是Numba
c++

C++ 确实牛逼,才 秒,不过好戏还在后头,现在我们使用 Numba 来加速一下,操作很简单,不需要改动原有的代码,先导入 Numba 的 njit,再在函数上方放个装饰器 @njit 即可,其他保持不变,代码如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

import math
import time
from numba import njit

# @njit 相当于 @jit(nopython=True) 
@njit
def is_prime(num):
    if num == 2:
        return True
    if num <= 1 or not num % 2:
        return False
    for div in range(3, int((num) + 1), 2):
        if not num % div:
            return False
    return True

@njit
def run_program(N):
    total = 0
    for i in range(N):
        if is_prime(i):
            total += 1
    return total


if __name__ == "__main__":
    N = 10000000
    start = ()
    total = run_program(N)
    end = ()
    print(f"total prime num is {total}")
    print(f"cost {end - start}s")

运行一下,可以看出时间已经从 秒降低到 3 秒。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

total prime num is 664579
cost 

相比 C++ 的 秒还是有一点慢,你可能会说 Python 还是不行啊。等一等,我们还有优化的空间,就是 Python 的 for 循环,那可是 1000 万的循环,对此,Numba 提供了 prange 参数来并行计算,从而并发处理循环语句,只需要将 range 修改为 prange,装饰器传个参数:parallel = True,其他不变,代码改动如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

import math
import time
from numba import njit, prange

@njit
def is_prime(num):
    if num == 2:
        return True
    if num <= 1 or not num % 2:
        return False
    for div in range(3, int((num) + 1), 2):
        if not num % div:
            return False
    return True

@njit(parallel = True)
def run_program(N):
    total = 0
    for i in prange(N):
        if is_prime(i):
            total += 1
    return total


if __name__ == "__main__":
    N = 10000000
    start = ()
    total = run_program(N)
    end = ()
    print(f"total prime num is {total}")
    print(f"cost {end - start}s")

现在运行一下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

python isPrime.py
total prime num is 664579
cost 

才 秒,比 C++ 还快,Numba 真的牛逼!我又运行了两次,确认自己没看错,平均就是 秒:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

谁更快?Python pk C++,原来主角是Numba
Python

看到这里,Numba 又让我燃起了对 Python 的激情,我不转 C++ 了,Python 够用了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

Numba 如何做到的呢?官方文档这样介绍:它读取装饰函数的 Python 字节码,并将其与有关函数输入参数类型的信息结合起来,分析和优化代码,最后使用编译器库(LLVM)针对你的 CPU 生成量身定制的机器代码。每次调用函数时,都会使用此编译版本,你说牛逼不?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

Numba 还有更多详细的用法,这里不多说,想了解的请移步官方文档[1]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

最后的话

Python 几乎在每一个领域都有对应的解决方案,本文提到的 Numba 库就是专门解决 Python 在计算密集型任务方面性能不足的问题,如果你从事机器学习、数据挖掘等领域,这个会非常有帮助文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/21897.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/ymba/21897.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定