сравнивая питон с с / фортран - PullRequest
12 голосов
/ 25 февраля 2012

Я написал следующие программы для сравнения скорости python с c / fortran.Чтобы получить время, используемое программами, я использовал команду «время».Все программы вычисляют квадратный корень из x x + y y + z * z, где x, y, z - числа с плавающей точкой.Я использовал корневой квадрат, потому что это одна из самых трудоемких частей в научных вычислениях, в которой я участвую.Тест, который я сделал, я обнаружил, что Python не рекомендуется для научных вычислений.Но, вероятно, мой код очень неэффективен.

Как вы думаете, я мог бы сделать свой код более эффективным только для этого простого теста?

Фортран:

program root_square
implicit none

integer i,j
real x,y,z,r

x=1.0
y=2.0
z=3.0

do j=1,3000
    do i=1,1000000
        r=sqrt(x*x+y*y+z*z)
    enddo
enddo

end program root_square

C:

#include "stdio.h"
#include "math.h"

int main (void)
{

float x=1.0,y=2.0,z=3.0,r;
int i,j;

for(j=0; j<3000; j++){
        for(i=0; i<1000000; i++) {
                r=sqrt(x*x+y*y+z*z);
        }
}

return 0;
}

Python:

#!/usr/bin/env python

from math import sqrt

x = 1.0
y = 2.0
z = 3.0

for j in range(1,3001):
  for i in range(1,1000001):
    r = sqrt(x*x+y*y+z*z)

Ответы [ 8 ]

14 голосов
/ 25 февраля 2012

Я недавно провел аналогичный тест с более реалистичным алгоритмом реального мира. Он включает в себя Numpy, Matlab, FORTRAN и C # (через ILNumerics ). Без определенных оптимизаций Numpy генерирует гораздо менее эффективный код, чем другие. Конечно, как всегда, это может указывать только на общую тенденцию. Вы сможете написать код на Фортране, который в конце будет работать медленнее, чем соответствующая реализация. Но в большинстве случаев NumPy будет гораздо медленнее. Вот (усредненные) результаты моего теста:

kmeans comparison results

Чтобы рассчитать время таких простых операций с плавающей запятой, как в вашем примере, все сводится к способности компиляторов генерировать «оптимальные» машинные инструкции. Здесь не так важно, сколько этапов компиляции задействовано. .NET и numpy используют более одного шага, сначала компилируя в байтовый код, который выполняется на виртуальной машине. Но варианты для оптимизации результата в равной степени существуют - в теории. На практике современные компиляторы FORTRAN и C лучше оптимизируют скорость выполнения. В качестве одного примера они используют расширения с плавающей запятой (SSE, AVX) и лучше развертывают циклы. Numpy (или лучше CPython, который в основном используется Numpy), кажется, работает хуже в этой точке. Если вы хотите убедиться, какая среда лучше всего подходит для вашей задачи, вы можете подключиться к отладчику и исследовать окончательные машинные инструкции исполняемого файла.

Однако имейте в виду, что в более реалистичном сценарии производительность с плавающей запятой важна только в самом конце большой цепочки оптимизации. Различие часто маскируется гораздо более сильным эффектом: пропускной способностью памяти. Как только вы начнете обрабатывать массивы (что часто встречается в большинстве научных приложений), вам придется учитывать стоимость управления памятью. Структуры отклоняются в поддержке автора алгоритма в написании эффективных алгоритмов памяти. По моему мнению, numpy усложняет написание алгоритмов, эффективно использующих память, чем FORTRAN или C. Но это нелегко для любого из этих языков. (ILNumerics значительно улучшает это.)

Другим важным моментом является распараллеливание. Поддерживает ли фреймворк выполнение ваших вычислений параллельно? И насколько это эффективно? Опять же мое личное мнение: ни C, ни FORTRAN, ни Numpy не позволяют легко распараллелить ваши алгоритмы. Но FORTRAN и C по крайней мере дают вам возможность сделать это, даже если иногда требуется использование специальных компиляторов. Другие фреймворки (ILNumerics, Matlab) распараллеливаются автоматически.

Если вам нужна «пиковая производительность» для очень маленьких, но дорогостоящих алгоритмов, вам в основном будет лучше использовать FORTRAN или C. Только потому, что они в конце генерируют лучший машинный код (в однопроцессорной системе). Однако написание более крупных алгоритмов на C или FORTRAN и с учетом эффективности использования памяти, параллелизма и часто становится громоздким. Здесь языки более высокого уровня (такие как numpy, ILNumerics или Matlab) превосходят языки более низкого уровня. И если все сделано правильно - разница в скорости выполнения часто ничтожна. К сожалению, это часто не так в случае с NumPy.

5 голосов
/ 25 февраля 2012

Ошибочный бенчмарк.

Если вы хотите рассчитать время арифметики с плавающей запятой, то вам следует в первый раз, когда циклы ничего не делают (или настолько близки к нулю, насколько вы можете управлять).Чтобы избежать оптимизации всего цикла, убедитесь, что он выполняет что-то вроде перемещения однобайтового символа из одного массива в другой.

Затем снова рассчитайте его с вычислением с плавающей запятой и вычтите первое время, чтобы получить большеточное число.

Кроме того, Python имеет только двойные числа с плавающей запятой, поэтому более четный тест обеспечит использование другими языками с плавающей запятой.И как уже упоминали другие, Python широко используется для научных вычислений, но эти ученые обычно используют библиотеку numpy для выполнения матричных вычислений, а не для написания циклов Python.

4 голосов
/ 25 февраля 2012

Имейте в виду, что вычисление r не зависит от переменных цикла, поэтому оптимизирующий компилятор может вывести вычисление из цикла и просто запустить пустой цикл требуемое количество раз;или даже полностью удалить этот цикл и выполнить только вычисление квадратного корня.
Настоящий умный оптимизатор может заметить, что вы ничего не делаете с результатом, поэтому вся программа может быть оптимизирована без изменения вывода (т. е.нет ничего).

4 голосов
/ 25 февраля 2012

Как правило, numpy используется для научных расчетов в python. Вы, вероятно, должны проверить эту библиотеку.

3 голосов
/ 25 февраля 2012

вероятно, вы можете. Существует множество математических библиотек для Python, которые, вероятно, могут сделать задачу, которую вы хотите, немного более эффективной. Поскольку диапазоны python работают совершенно иначе, чем циклы c, я бы сначала попытался развернуть эти циклы.

3 голосов
/ 25 февраля 2012

Вы точно не объяснили, какова цель вашего измерения, поэтому очень трудно ответить, собирается ли ваш тестовый код адекватно предоставить вам информацию для достижения этой цели.В целом, существуют тесты, которые говорят вам нечто очень конкретное - вы должны точно знать, что вы пытаетесь выяснить, выполняя тест.Микробенчмарки того типа, который вы пробовали выше, также известны тем, что дают искаженные ответы ...

2 голосов
/ 25 февраля 2012

Есть несколько вещей, о которых вы должны знать, прежде чем начинать сравнивать такие моменты времени.

  1. Как уже упоминалось в другом ответе, возможно, компилятор оптимизирует цикл и фактическое значение.далеко.Более того, даже если вы напечатаете результат, он может просто предварительно вычислить квадратный корень.
  2. Вы используете real в Fortran и float в C, поэтому (в зависимости от вашей системы, конечно)компилятор, вероятно, будет использовать библиотечный вызов sqrtf в fortran, в то время как в C вы используете sqrt вместо sqrtf, который вы должны использовать для float.
  3. В Python вы должны использоватьПакеты numpy и scipy , они предоставляют массивы, в которых вы можете выполнять эффективные операции с целым массивом, избегая циклического выполнения в Python.
0 голосов
/ 25 февраля 2012

для расчетов я могу попробовать haskell или ml ...

попробуйте этот код в ML:

fun trip(x,y,z) = if y=z then 0
    else trip(((Math.sqrt((1.0*1.0)+(2.0*2.0)+(3.0*3.0)))*1.0),(y+1),z);
trip(1.0,1,300000000);
...