Я начал использовать Джулию пару месяцев назад, решив попробовать после нескольких недель услышать, как люди хвалят различные особенности. Чем больше я узнал об этом, тем больше мне нравился его стиль, сглаживая легкость выражения концепций на языке высокого уровня с уделением особого внимания скорости и удобству использования. Я реализовал модель, которую я также написал на С++ и R в Julia, и обнаружил, что версия Julia работает намного быстрее, чем версия R, но все же немного медленнее, чем С++. Тем не менее, код был более разборчивым в Джулии, чем в обоих других языках. Это стоит многого, и, в частности, поскольку я обобщил модель, объем работы по расширению сферы действия кода Julia был намного меньше, чем сопоставимое количество работающих, которым угрожали быть на других языках.
В последнее время я сосредоточился на том, чтобы мой код Julia работал быстрее, потому что мне нужно запустить эту модель триллионов раз. При этом я руководствовался @code_warntype
, @time
, @profile
и ProfileView
и флагом track-allocation
. Отлично. Этот инструментарий не так хорош, как инструмент профилирования некоторых других языков, но он все еще указал на множество узких мест.
То, что я нахожу, это то, что у меня в моем коде есть именно выразительность высокого уровня, которая мне нравится в Julia, и когда я переписываю эту экспрессивность, чтобы избежать ненужных распределений, я теряю эту очень выразительность. В качестве тривиального примера я недавно изменил строку кода, которая читала
sum([x*y for x in some_list, y in similar_list])
в цикл, который выполняет итерацию по спискам и добавляет к переменной состояния. Не ракетостроение, и я понимаю, почему это немного быстрее, не нужно выделять массив. На самом деле это намного быстрее. Таким образом, я сделал аналогичные вещи, избегая использования Dicts или составных типов, которые "чувствуют" право на проблему, когда я могу вместо этого просто вручную отслеживать индексы во временных параллельных массивах, стиль кодирования, который я ненавижу, но который, очевидно, запускает быстрее, когда я повторяю конкретную операцию по созданию и короткому использованию небольшой структуры данных много и много раз.
В целом, это в значительной степени прекрасно, потому что я принял близко к сердцу инструкции написать короткие методы, поэтому методы более высокого уровня, которые составляют поведение моих собственных более коротких методов, не должны "беспокоиться" о том, как короче методы работы; более короткие могут быть неуклюжими, чтобы читать, не делая ядро моей программы неуклюжей для чтения.
Но мне это интересно, я что-то "пропустил". Если вся суть языка (для меня как для конечного пользователя, не связанного с теорией), отчасти сочетает скорость с легкостью разработки/мысли/чтения/обслуживания и т.д., То есть быть доступным для записи и используемым языком технических вычислений, то это не значит, что я никогда не должен тратить время на то, чтобы подумать о самом быстром способе добавить кучу чисел, не следует переписывать "легко читаемый" или элегантный код, который использует сопоставления, фильтры и высокоуровневые функциональные концепции в "неуклюжий" код, который изобретает колесо, чтобы выразить эти вещи с точки зрения низкоуровневого отслеживания индексов массивов во всем мире? (Некоторая часть меня ожидает, что язык с таким большим количеством интеллекта за его дизайном достаточно умен, чтобы "выяснить", что на самом деле не нужно выделять новый массив, когда я пишу sum ([x * y]), и что Я просто слишком тупый, чтобы понять правильные слова, чтобы рассказать языком, что буквально "рассказывал" весь цикл бизнеса вручную. В какой-то момент я даже подумал о том, чтобы написать @macros
для "преобразования" некоторого быстро выраженного кода в длинные, но более быстрые циклические выражения, но я подумал, что я должен думать о проблеме не так, если я в основном пытаюсь расширить функции компилятора только для решения довольно простых проблем, что и заставило меня написать этот вопрос.)
Возможно, ответ "если вы хотите действительно совершенный код, вы платите цену, несмотря ни на что". Или иначе, быстрый код с досадно неприятными для чтения циклами, массивами, отслеживанием индексов и т.д. Находится на эффективной границе пространства компромиссов скорости. Если это так, это совершенно верно, и я бы не сказал, поэтому я думаю, что меньше Джулии. Мне просто интересно, действительно ли этот стиль программирования находится на границе, или если мой опыт - это то, что он есть, потому что я просто не программирую "хорошо" на этом языке. (По аналогии см. Вопрос Какая ваша наиболее продуктивная комбинация с Vim?, где принятый и отличный ответ по существу состоит в том, что ОП просто не "получил" его.) Я подозрительно, что, хотя мне удалось заставить язык делать большую часть того, что я хочу, t "получить" что-то, но у меня нет хорошего представления о том, что спросить, потому что я боюсь, что не получу неизвестное мне неизвестное.
TL; DR: Ожидается, что для лучшей практики в Julia я потрачу много времени на "разложение" вызовов функций высокого уровня в их примитивные реализации с точки зрения циклов и массивов, чтобы быстрее производительности, или это указывает на то, что я не думал о правильном программировании в/использовании языка?