F# кажется медленнее, чем другие языки... что я могу сделать, чтобы ускорить его?

Мне нравится F#; Я действительно, действительно делаю. Укушенный "функциональным программированием", я заставляю себя использовать его, когда у меня есть такая возможность. На самом деле, я недавно использовал его (во время недельного отпуска) для написания хорошего алгоритма ИИ.

Однако мои попытки до сих пор (см. SO вопрос, связанный с моей первой попыткой здесь), похоже, указывают на то, что, хотя, несомненно, красиво... F# имеет самую медленную скорость выполнения из всех языков, которые я использовал.

Я делаю что-то не так в своем коде?

Я подробно объясняю, что я сделал в своем посте в блоге, и в своих экспериментах я вижу, что OCaml и остальная часть группы работают в 5–35 раз быстрее, чем F#.

Я один такой с таким опытом? Я нахожу обескураживающим, что язык, который мне нравится больше всего, также является самым медленным - иногда намного...

РЕДАКТИРОВАТЬ: Прямая ссылка GitHub, где код живет в различных языковых формах...

РЕДАКТИРОВАТЬ 2: Благодаря Томасу и Дэниелу, скорость значительно улучшилась:

  • Наибольший прирост скорости: переход от "ref" к "mutable" дал колоссальные 30%.
  • Удаление исключений и использование while/flagChecks дало еще 16%.
  • Переход от дискриминационных союзов к перечислениям дал еще 5%.
  • "встроенный" дал 0,5-1%

РЕДАКТИРОВАТЬ 3: Доктор Джон Харроп присоединился к борьбе: ускорение на 60%, заставив ScoreBoard работать непосредственно с "перечисляемой" версией данных. Императивная версия F# теперь работает в 3-4 раза медленнее, чем C++, что является хорошим результатом для среды исполнения на основе виртуальной машины. Я считаю, что проблема решена - спасибо, ребята!

РЕДАКТИРОВАТЬ 4: После объединения всех оптимизаций, это - результаты (F# достиг C# в императивном стиле - теперь, если бы я только мог кое-что сделать с функциональным стилем, также!)

  • реальный 0m0.221s: это был C++
  • реальный 0m0.676s: это был C# (обязательно, зеркало C++)
  • реальные 0m0,704s: это был F# (обязательно, зеркало C++)
  • настоящий 0m0.753s: это был OCaml (обязательно, зеркало C++)
  • реальный 0m0.989s: это был OCaml (функционал)
  • реальные 0m1.064s: это была Java (обязательно)
  • реальный 0m1.955s: это был F# (функционал)

2 ответа

Решение

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

Я кратко рассмотрел ваш код и вот несколько (непроверенных) предложений.

  • Вы можете заменить дискриминационный союз Cell с перечислением (это означает, что вы будете использовать типы значений и целочисленное сравнение вместо ссылочных типов и тестов типов времени выполнения):

    type Cell =    
      | Orange = 1
      | Yellow = 2
      | Barren = 3
    
  • Вы можете пометить некоторые тривиальные функции как inline, Например:

    let inline myincr (arr:int array) idx =
      arr.[idx] <- arr.[idx] + 1
    
  • Не используйте исключения для потока управления. Это часто делается в OCaml, но исключения.NET работают медленно и должны использоваться только для исключений. Вы можете заменить for цикл в вашем образце с while loop и изменяемый флаг или с хвостовой рекурсивной функцией (хвостовая рекурсивная функция скомпилирована в цикл, поэтому она будет эффективной даже в императивном решении).

По сути, это не ответ, но пытались ли вы написать один и тот же код на F# и C#, т.е. императивный код F#? Скорость должна быть одинаковой. Если вы сравниваете краткий функциональный код с интенсивным использованием функций высшего порядка, выражений последовательности, ленивых значений, сложного сопоставления с образцом и т. Д. - все, что позволяет делать код более коротким, понятным (читаемым, более понятным) - ну, часто есть компромисс. Как правило, время разработки / обслуживания намного больше времени выполнения, поэтому обычно считается желательным компромиссом.

Некоторые ссылки:
F# и C# CLR то же самое, почему F# быстрее, чем C#
Сравнение производительности C# / F#
https://stackru.com/questions/142985/is-a-program-f-any-more-efficient-execution-wise-than-c

Еще один момент, который следует учитывать: на функциональном языке вы работаете на более высоком уровне, и становится очень легко не учитывать стоимость операций. Например, Seq.sort кажется достаточно невинным, но наивное использование этого может обречь производительность. Я бы порекомендовал изучить ваш код и спросить себя, понимаете ли вы стоимость каждой операции. Если вы не чувствуете рефлексию, более быстрый способ сделать это, конечно, с помощью профилировщика.

Другие вопросы по тегам