Насколько С++ быстрее Python



Книга Насколько С++ быстрее Python

Есть миллион причин любить 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.


Таблица 1) Сравнение время выполнения генерации 13-,14-,15-мер на Python и C++

Мы видим, что С++ выполняет одни и те же инструкции и алгоритм намного быстрее, чем Python. И для многих программистов и специалистов по данным это неудивительно, но этот эксперимент показывает, что разница в скорости колоссальна.


Ещё раз повторю, оба кода написаны самым простым способом (и возможно, самым неэффективным). В Python существует множество других подходов, улучшающих производительность кода, и вам стоит их опробовать.


from itertools import product
for i in product(['A', 'C', 'G'], repeat=10):
print(''.join(i))

Кроме того, в этом эксперименте не использовалось распараллеливание центрального (CPU) и графического (GPU) процессов, необходимое в подобных задачах (задачи чрезвычайной параллельности). Также мы почти не нагружали память. Если фиксировать результаты (для какой-либо цели), то процесс управления памяти приведёт к ещё большему “отрыву” между С++ и Python.


Этот пример и многие другие задачи говорят о том, что даже специалистам по данным нужно знать такие языки, как С++, если они работают с огромным объемом данных или с теми, что растут в геометрической прогрессией.


589   0  

Comments

    Ничего не найдено.