Есть миллион причин любить Python (особенно специалистам по данным). Но сильно ли он отличается от более профессиональных низкоуровневых языков программирования, таких как С или С++? Скорее всего, многие дата-специалисты или пользователи Python задавались этим вопросом или однажды задумаются об этом. Python и такие языки, как С++, во многом отличаются друг от друга. И в этой статья мы посмотрим, насколько С++ быстрее Python на очень простом примере.
Я не стал брать выдуманное задание, а решил показать их различия на простой и практичной задаче. Заключается она в том, чтобы сгенерировать все возможные k-меры последовательности ДНК при указанном значении k (для тех, кто не знает, что такое k-мер ДНК, объясню простым языком в следующем разделе). Я выбрал этот пример, потому что многие задачи по обработке и анализу геномных данных (напр. генерация k-меры) требуют множество вычислительных работ. Именно поэтому многих специалистов по данным в биоинформатике привлекает С++ (в дополнение к Python).
ВАЖНОЕ ПРИМЕЧАНИЕ: В этой статье не сравнивается С++ и Python в их самом эффективном использовании. Оба кода можно написать гораздо лучшем способом, применяя более продуманные подходы. Единственная цель статьи — сравнить два языка при использовании абсолютно одинаковых инструкций и одного алгоритма.
Кратко о k-мер ДНК
ДНК — это длинная цепь блоков, называемых нуклеотидами. В состав ДНК входит 4 типа нуклеотидов, которые обозначаются буквами A, C, G и T. Человек (а точнее Homo Sapiens) содержит 3 миллиарда нуклеотидных пар. Например, маленькая часть человеческого ДНК может выглядеть вот так:
ACTAGGGATCATGAAGATAATGTTGGTGTTTGTATGGTTTTCAGACAATT
Если вы возьмёте из этой строки любую последовательность из 4 нуклеотидов (т.е. букв), то получите k-мер с длинною 4 (называемая 4-мер). Вот несколько примеров 4-мер, образованных из этой части ДНК.
ACTA
, CTAG
, TAGG
, AGGG
, GGGA
и т.д.
Задача
В этой статье мы сгенерируем все возможные 13-мер. С точки зрения математики, здесь нужно применить метод подстановки. Следовательно, получаем ⁴¹³ (=67,108,864) возможных 13-меров. Чтобы сгенерировать результаты в С++ и Python, я воспользуюсь простым алгоритмом. Посмотрим решения и сравним их.
Сравнение решений
Чтобы было проще сравнить С++ и Python в этой конкретной задаче, я взял совершенно одинаковый алгоритм для обоих языков и намерено написал простые и похожие коды. Я не стал использовать сложные структуры данных и сторонние пакеты или библиотеки. Первый код написан в Python.
def convert(c):
if (c == 'A'): return 'C'
if (c == 'C'): return 'G'
if (c == 'G'): return 'T'
if (c == 'T'): return 'A'
print("Start")
opt = "ACGT"
s = ""
s_last = ""
len_str = 13
for i in range(len_str):
s += opt[0]
pos = 0
counter = 1
while (s != s_last):
counter += 1
# Чтобы вывести все k-меры, уберите комментарий со следующей строки.
# print(s)
change_next = True
for i in range(len_str):
if (change_next):
if (s[i] == opt[-1]):
s = s[:i] + convert(s[i]) + s[i+1:]
change_next = True
else:
s = s[:i] + convert(s[i]) + s[i+1:]
break
# Чтобы вывести все k-меры, уберите комментарий со следующей строки.
# print(s)
print("Number of generated k-mers: {}".format(counter))
print("Finish!")
Код на Python сгенерировал все 67 миллионов 13-меров за 61,23 секунд. Справедливости ради, я закомментировал строчки, которые выводили k-меры (строчки 25 и 37). Если же вы хотите видеть все k-меры во время генерации, уберите комментарий с этих двух строчек.
Примечание. Для вывода всех k-мер потребуется много времени. При необходимости, воспользуйтесь CTRL+C для прекращения выполнения кода.
Теперь посмотрим на тот же алгоритм в С++.
#include <iostream>
#include <string>
using namespace std;
char convert(char c)
{
if (c == 'A') return 'C';
if (c == 'C') return 'G';
if (c == 'G') return 'T';
if (c == 'T') return 'A';
return ' ';
}
int main()
{
cout << "Start" << endl;
string opt = "ACGT";
string s = "";
string s_last = "";
int len_str = 13;
bool change_next;
for (int i=0; i<len_str; i++)
{
s += opt[0];
}
for (int i=0; i<len_str; i++)
{
s_last += opt.back();
}
int pos = 0;
int counter = 1;
while (s != s_last)
{
counter ++;
// Чтобы вывести все k-меры, уберите комментарий со следующей строки.
// cout << s << endl;
change_next = true;
for (int i=0; i<len_str; i++)
{
if (change_next)
{
if (s[i] == opt.back())
{
s[i] = convert(s[i]);
change_next = true;
} else {
s[i] = convert(s[i]);
break;
}
}
}
}
// Чтобы вывести все k-меры, уберите комментарий со следующей строки.
// cout << s << endl;
cout << "Number of generated k-mers: " << counter << endl;
cout << "Finish!" << endl;
return 0;
}
После компиляции код сгенерировал все 67 миллионов 13-меров за 2,42 секунд. То есть, С++ выполняет один и тот же код в 25 раз быстрее, чем Python. Я повторил эксперимент с 14-мером и 15-мером (нужно изменить строчку 12 в Python и 22 в С++). Результаты приведены в Таблице 1.
Мы видим, что С++ выполняет одни и те же инструкции и алгоритм намного быстрее, чем Python. И для многих программистов и специалистов по данным это неудивительно, но этот эксперимент показывает, что разница в скорости колоссальна.
Ещё раз повторю, оба кода написаны самым простым способом (и возможно, самым неэффективным). В Python существует множество других подходов, улучшающих производительность кода, и вам стоит их опробовать.
from itertools import product
for i in product(['A', 'C', 'G'], repeat=10):
print(''.join(i))
Кроме того, в этом эксперименте не использовалось распараллеливание центрального (CPU) и графического (GPU) процессов, необходимое в подобных задачах (задачи чрезвычайной параллельности). Также мы почти не нагружали память. Если фиксировать результаты (для какой-либо цели), то процесс управления памяти приведёт к ещё большему “отрыву” между С++ и Python.
Этот пример и многие другие задачи говорят о том, что даже специалистам по данным нужно знать такие языки, как С++, если они работают с огромным объемом данных или с теми, что растут в геометрической прогрессией.
Читайте также:
- 4 совета по работе с потоками и мьютексами в C++
- Распознаём 50 видов текста на C++ с Plywood
- 9 Уровней применения функции zip в Python
Читайте нас в Telegram, VK и Дзен
Перевод статьи Naser Tamimi: How Fast Is C++ Compared to Python?