В этой статье автор разобрался, как увеличить скорость работы Python, и продемонстрировал реализацию на реальном примере.
Прим. ред. Это перевод. Мнение редакции может не совпадать с мнением автора оригинала.
Блок-схема алгоритма генерации простых чисел
from time import per_counter
def is_prime(num):
if num == 2:
return True;
if num <= 1 or not num % 2:
return False
for div in range(3,int(math.sqrt(num)+1),2):
if not num % div:
return False
return True
def run program(N):
for i in range(N):
is_prime(i)
if __name__ == ‘__main__’:
N = 10000000
start = perf_counter()
run_program(N)
end = perf_counter()
print (end — start)
#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 main()
{
int N = 10000000;
clock_t start,end;
start = clock();
for (int i; i < N; i++) isPrime(i);
end = clock();
cout << (end — start) / ((double) CLOCKS_PER_SEC);
return 0;
}
pip install numba
from time import per_counter
from numba import njit, prange
@njit(fastmath=True, cache=True)
def is_prime(num):
if num == 2:
return True;
if num <= 1 or not num % 2:
return False
for div in range(3,int(math.sqrt(num)+1),2):
if not num % div:
return False
return True
@njit(fastmath=True, cache=True,parallel=True)
def run program(N):
for i in prange(N):
is_prime(i)
if __name__ == ‘__main__’:
N = 10000000
start = perf_counter()
run_program(N)
end = perf_counter()
print (end — start)
***
Как вы могли заметить, в коде добавились декораторы njit:
Источник статьи: https://tproger.ru/translations/python-mozhet-byt-bystree-c/
Прим. ред. Это перевод. Мнение редакции может не совпадать с мнением автора оригинала.
Тест базовой скорости
Для сравнения базовой скорости Python и C++ я буду использовать алгоритм генерации случайных простых чисел.Блок-схема алгоритма генерации простых чисел
Реализация на Python
import mathfrom time import per_counter
def is_prime(num):
if num == 2:
return True;
if num <= 1 or not num % 2:
return False
for div in range(3,int(math.sqrt(num)+1),2):
if not num % div:
return False
return True
def run program(N):
for i in range(N):
is_prime(i)
if __name__ == ‘__main__’:
N = 10000000
start = perf_counter()
run_program(N)
end = perf_counter()
print (end — start)
Реализация на C++
#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 main()
{
int N = 10000000;
clock_t start,end;
start = clock();
for (int i; i < N; i++) isPrime(i);
end = clock();
cout << (end — start) / ((double) CLOCKS_PER_SEC);
return 0;
}
Результат
- Python: скорость выполнения 80,137 секунд;
- C++: скорость выполнения 3,174 секунды.
Комментарий
Как и ожидалось, программа на C++ выполняется в 25 раз быстрее, чем на Python. Ожидания подтвердились, потому что:- Python — это динамически типизированный язык;
- GIL(Global Interpreter Lock) — не поддерживает параллельное программирование.
Numba
Чтобы начать использовать Numba, просто установите её через консоль:Numba — это Open Source JIT-компилятор, который переводит код на Python и NumPy в быстрый машинный код.
pip install numba
Реализация на Python с использованием Numba
import mathfrom time import per_counter
from numba import njit, prange
@njit(fastmath=True, cache=True)
def is_prime(num):
if num == 2:
return True;
if num <= 1 or not num % 2:
return False
for div in range(3,int(math.sqrt(num)+1),2):
if not num % div:
return False
return True
@njit(fastmath=True, cache=True,parallel=True)
def run program(N):
for i in prange(N):
is_prime(i)
if __name__ == ‘__main__’:
N = 10000000
start = perf_counter()
run_program(N)
end = perf_counter()
print (end — start)
***
Как вы могли заметить, в коде добавились декораторы njit:
- parallel=True — включает параллельное выполнение программы на процессоре;
- fastmath=True — разрешает использование небезопасных преобразований с плавающей точкой;
- cache=True— позволяет сократить время компиляции функции, если она уже была скомпилирована.
Итоговая скорость Python
- Python: скорость выполнения 1,401 секунды;
- C++: скорость выполнения 3,174 секунды.
Источник статьи: https://tproger.ru/translations/python-mozhet-byt-bystree-c/