Подтвердить что ты не робот

Я правильно использую Джулию?

Я начал использовать Джулию пару месяцев назад, решив попробовать после нескольких недель услышать, как люди хвалят различные особенности. Чем больше я узнал об этом, тем больше мне нравился его стиль, сглаживая легкость выражения концепций на языке высокого уровня с уделением особого внимания скорости и удобству использования. Я реализовал модель, которую я также написал на С++ и 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 я потрачу много времени на "разложение" вызовов функций высокого уровня в их примитивные реализации с точки зрения циклов и массивов, чтобы быстрее производительности, или это указывает на то, что я не думал о правильном программировании в/использовании языка?

4b9b3361

Ответ 1

Я думаю, что эта тема тесно связана с обсуждением, которое уже происходит в группе пользователей Julia Неужели Джулия действительно решает проблему с двумя языками?, и я хотел бы привести здесь один абзац из этого обсуждения:

@Stefan Karpinski:

Существуют разные стили и уровни написания кода в каждом язык. Там очень абстрактные С++ и там низкоуровневые курсор С++, который в основном C. Даже в C есть void * -тип программирования, который эффективно динамически типизирован без безопасности. Учитывая этот факт, я не уверен, что решение двух языковая проблема будет выглядеть с точки зрения этого поста позируют. Выполнение только одного стиля программирования звучит как проблема для меня это не решение. Напротив, я думаю, что одна из наибольшая сила заключается в его способности учитывать очень широкий диапазон стилей и уровней программирования.

Мой собственный опыт программирования Julia показывает, что он может заполнить пустую коробку современного языка программирования, которая может принести функции высокого уровня, такие как параллельная обработка, сервер сокетов и... в руках ученых, инженеров и всех гуру вычислений и прагматичные программисты, которые хотят сделать свою работу эффективным, поддерживаемым и читаемым образом, используя язык программирования все-в-одном.
По-моему, вы правильно используете Юлию, Джулия, как и другие языки, представляет разные стили программирования для разных ситуаций, вы можете оптимизировать узкие места для скорости и держать другие части более читабельными. также вы можете использовать такие инструменты, как Devectorize.jl, чтобы избежать проблемы с переписыванием.

Ответ 2

Это трудный вопрос, чтобы ответить удовлетворительно. Поэтому я постараюсь внести небольшой вклад в надежду, что "банк" разных мнений может быть достаточно хорошим. Итак, вот 3 мнения, которые переживают сейчас:

  • Язык программирования можно сравнить с объектом с импульсом. Пользовательская база - это ее масса и их стили, оказывающие на нее силу. Первоначальные пользователи/разработчики могут тянуть язык в определенном направлении, потому что он все еще имеет низкую массу. Язык может развиваться, даже если он чрезвычайно популярен (например, C/С++), но это сложнее. Будущее Джулии все еще неписано, но его обещание находится в начальном направлении, проникнутом его создателями и ранними пользователями.

  • Оптимизация лучше задерживается до тех пор, пока правильность не будет хорошо протестирована. "Преждевременная оптимизация - это корень всего зла" (Д. Кнут). Это никогда не больно вспоминать об этом, снова. Таким образом, сохранение кода, читаемого и правильного, лучше всего до этапа оптимизации, который может запутать ограниченные области кода.

  • Выражение sum([x*y ...]) может потребовать, чтобы компилятор был слишком умным, и было бы лучше просто определить a sumprod(x,y). Это позволило бы sumprod использовать универсальную структуру рассылки Julia и оптимизироваться для x и y и, возможно, позже оптимизирован для специально введенных x и y.

Что это, на данный момент. Мнений много. Поэтому продолжим обсуждение.

Ответ 3

Не могли бы вы написать класс, который абстрагирует эти понятия для вас (например, FastDict или FastList или что-то еще)? Тогда у вас будет такая же удобочитаемость (если немного больше черного ящика), имея код исполнения.

Ответ 4

Предыстория: я программист R/Rcpp, который использует Джулию около месяца. По крайней мере, половина кода R, который я написал, называет C++ код, который я написал.

Вывод: я думаю, что Юлия решает проблему двух языков программирования так, как это возможно. Это не означает, что можно написать высокопроизводительный код, как если бы он был родным R/Python, но это значительно снижает объем работы, необходимой для написания высокопроизводительной программы, которая может быть легко использована другими.

Дальнейшее обсуждение: Прежде всего, я считаю, что просто невозможно написать высокопроизводительный код без некоторой заботы о проблемах типа C/C++, то есть объявления типов, обдумывания эффективных структур данных, а не читаемых структур данных и т.д. Поэтому я считаю, что если кто-то надеется, что у них будет высокопроизводительный язык, на котором не нужно заботиться о структурах данных, им не повезло. Конечно, я статистик, а не специалист по CS, поэтому я допускаю, что могу ошибаться.

Тем не менее, я немного удивлен тем, как много рабочего времени уходит на Джулию. В частности, большая часть моей работы включает в себя сначала написание некоторого кода C++ для некоторой вычислительной части. После этого я в основном пишу обертки R и процессоры данных на нативном R, чтобы подготовить данные для моего кода C++. Предварительная обработка, как правило, не требует больших вычислительных затрат, и у R есть масса хороших инструментов для этого. Если все тщательно спланировано заранее, это теоретически не такой уж плохой процесс.

Тем не менее, на самом деле происходит то, что я все запускаю и запускаю, а потом понимаю, что хочу изменить код C++ по тем или иным причинам. Вот тут и начинаются огромные головные боли. К сожалению, на этом этапе я часто получаю две версии всех моих данных; один, который передает вещи в кучу собственных инструментов предварительной обработки R, и другой, который передает вещи как объекты C++. Взлом с некоторыми объектами C++ может иметь много последствий для всех объектов R. Честно говоря, я трачу слишком много времени, пытаясь разобраться со всем этим.

Мой опыт с Юлией так далеко, что эта головная боль прошла. Больше нет версии R и C++ версии данных, с которыми я работаю. Просто Юля. Это также означает, что действительно легко ввести код других людей в высокопроизводительную часть моего кода. В качестве недавнего примера я хотел поработать с ковариационной функцией Matern. Это нетривиальная функция, и мне не хочется реализовывать ее самостоятельно. Я могу найти множество людей, у которых пакеты R реализованы с хорошими, хорошо документированными вызовами на родном R. Однако в моем случае я действительно хотел бы вызвать это из C++ без всех собственных издержек R. Это означает, что (а) мне нужно искать всех, кто не обязательно хорошо документирован, или не обязательно удобный для пользователя код C++ в их пакете R, или (б) изобретать велосипед. С другой стороны, если бы я использовал Джулию, должно получиться так, что если кто-то напишет хорошую ковариационную функцию Matern для всего мира, я смогу использовать ее напрямую, а не копаться в своем коде для вызова, который я на самом деле хочу использовать.

Возможно, что когда я начну создавать более сложные проекты Джулии, у меня могут появиться некоторые неприятности, о которых я пока не знаю. Но пока, кажется, действительно улучшается процесс объединения простых в использовании инструментов (например, R, Python-подобных вызовов) с высокопроизводительным кодом.