Пост 4. Многозадачная Юля.

Привествую друзья!

Сегодня мы поговорим о языке, на котором реализован практически весь функционал проекта jevo. А именно, о Julia.

Но перед тем, как мы начнем говорить о девочках, хочу напомнить о том, что часть из того, что описано здесь есть так же в моем видео блоге.

Я более чем уверен, что Вы не слышали о Julia. Не слышали, так как этот язык достаточно молод. Он появился в 2012 усилиями трех друзей из MIT. Вот, что пишет о нем wikipedia: “Julia — высокоуровневый высокопроизводительный свободный язык программирования с динамической типизацией, созданный для математических вычислений. Эффективен также и для написания программ общего назначения. Синтаксис языка схож с синтаксисом других математических языков (например, MATLAB и Octave), однако имеет некоторые существенные отличия. Julia написана на Си, C++ и Scheme. В стандартный комплект входит JIT-компилятор на основе LLVM, благодаря чему, по утверждению авторов языка, приложения, полностью написанные на языке, практически не уступают в производительности приложениям, написанным на статически компилируемых языках вроде Си или C++. Большая часть стандартной библиотеки языка написана на нём же. Также язык имеет встроенную поддержку большого числа команд для распределенных вычислений.”. Неплохо, правда? 🙂 Для первого знакомства, рекомендую Вам посмотреть 4 вводных урока вот здесь.

Отвечая на вопрос: “почему ты выбрал именно его?”, я скажу: “на первый взгляд, он содержал все, что нужно для этой задачи”. А именно (сверху наиболее важные):

  • производительность близкая к языку С. Одна из основных проблем таких систем в том, что они очень сильно “нагружают” процессор. По этому, не терять скорость на этом этапе для нас очень критично.
  • “зеленые” потоки. Изначально, я планировал использовать что-то(какую-то технологию), что давало бы возможность запускать очень много независимых процессов. При чем проблемы синхронизации должны отсутствовать. Оригинальные системные потоки не подходят для этого, так как они слишком медленные. При переключении между ними, процессор тратит очень много тактов да и синхронизация данных задача непростая. По-этому выбор пал на виртуальные или “зеленые” потоки.
  • возможность динамически модифицировать свой код. По сути – это метапрограммирование или возможность дописывать, удалять или модифицировать свой же код без перезапуска программы. Именно так должны поступать организмы в случае мутаций. По сути, им нужно перекомпилировать свой исходный код в машинный и запустить его в режиме реального времени. В jevo этим занимается специальный модуль – Mutator. Видео урок о метапрограммировании Вы можете найти здесь.
  • поддержка работы с сетью. Наша задача требует распределенных вычислений для ускорения работы системы в целом. Удаленный терминал, визуализатор, менеджеры и другие компоненты jevo используют сеть для “общения” с сервером(менеджером). Детальнее о работе с сетью Вы можете узнать из этого обучающего видео.
  • кроссплатформенный. Согласитесь, сегодня без этого никак 🙂
  • лицензия MIT. Моя душа склоняется к открытым системам 🙂
  • динамическая типизация. Это просто упрощает жизнь разработчикам.
  • встроенная система управления пакетами. Этот пункт очень важен, так как он в значительной мере помогает разработчикам решать рутинные и прикладные задачи. jevo использует множество пакетов. Например: Cairo для работы с canvas, GR – для OpenGL графики, FactCheck для тестов и т.д.
  • активное сообщество.

Если быть до конца чесным, то стоит упомянуть о том, что первая версия этой системы была написана на JavaScript 😛 Это была достаточная фриковая и нереальная идея по той причине, что системы реального времени на JS писать попросту нельзя 🙂 Был даже разработан простой ассемблер для генерации кода организмов… Но, так как этот язык имеет серъезные архитектурные ограничения (например, невозможность писать приложения реального времени с бесконечным главным циклом), увы, ничего не получилось. В любом случае исходный код есть на github, и вы можете с ним познакомиться. Продолжая, стоит так же упомянуть о минусах Julia:

  • Язык молод и содержит ошибки. Лично я запостил 4 критические ощибки в github репозиторий авторов (вот пример одной из них).
  • Среднее кол-во библиотек. Не смотря на активное развитие инфраструктуры языка, есть задачи, которые прийдется решать вручную или использовать библиотеки на C и Python.
  • Нет полноценной поддержки отладки. Есть лишь альтернативный дебаггер. Он он появится в v0.5.

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

helloWorlds.jl

Код вполне читабельный и не нуждается в дополнительном объяснении. Обратите внимание, на то, что аргумент msg не типизирован. Julia мягко относится к отсутствию типов. По умолчанию, таким переменным присваивается тип Any. Разница в коде с фиксированными типами и коде без фиксации в скорости его выполнния. Хотя, в данном примере – это не будет заметно. Хорошо, двигаемся дальше. Основной базовой еденицей программ на Julia является модуль. Он инкапсулирует в себе функции и, иногда данные. Такие данные называют глобальными в пределах модуля (хотя, авторы языка не рекомендуют использовать их из за уменьшения прозводительности). Так же, модуль – это своеобразное пространство имен в вашей программе, которое собирает внутри себя функции связанные логически. Модули могут использовать другие модули внутри себя. Но давайте обо всем по порядку. Создадим простой модуль:

helloWorldModule.jl

В коде выше, мы добавили несколько новых элементов. Комментарий сверху (формируется с помощью символа решетки (#)) и модуль – создается с помощью ключевого слова module. Пока все просто. Давайте сохраним этот код в отдельный файл с именем Hello.jl. Использование нашего модуля дело не сложное – все, что нам нужно, это подключить его в коде и вызвать функцию showMessage с помощью оператора “.” точка, вот так:

appHello.jl

Давайте сохраним этот код в файле AppHello.jl в той же папке, где мы сохранили Hello.jl. Супер! У нас есть два файла и мы можем их запустить. Для этого на Вашем компьютере должна быть установлена Julia. Скачать простой инсталлятор можно здесь. Нужно будет поскролить чуть ниже и выберать свою версию OS для скачивания. Скачали? Прекрасно d:) Давайте запустим все это:

cmdLineRun

Упс 🙂 Julia не может найти модуль Hello. Все по-тому, что она ищет его не там, где нужно. А нужно чтобы она искала его в текущей папке. Дело в том, что по умолчанию все модули должны находиться в специальной папке. На моем компьютере это c:\Users\<user-name>\.julia\v0.4\. Чтобы решить эту проблему, нам нужно указать список папок, где могут находиться модули и где Julia будет их искать. Давайте немного исправим наш код:

helloWorldModuleFixed

И запустим все снова:

cmdLineRunFixed

Вуаля. Все работает. Продолжим 🙂 Давайте рассмотрим что-то посложнее, а именно виртуальные или зеленые потоки. Идея зеленых потоков состоит в том, что  Вы можете создать множество (на много больше, чем системных) виртуальных потоков и управлять ими своими руками. То есть, Вы выступаете в роли процессора, который переключается мижду такими потоками в тот момент, когда это нужно. Пока все понятно? Если нет, то прочтите статью на википедии и погуглите немного 🙂 Важно понимать, что все эти “зеленые” друзья выполняются внутри одного – системного. Плюсы такого подхода в том, что на переключение между ними уходит минимум времени (значительно меньше, чем на системных братьев). И это дает значительное приимущество в скорости выполнения. Итак, рассмотрим пример:

task

С точки зрения Julia, поток – это функция, в которую можно входить и выходить в нескольких местах. Эта концепция хорошо описывается термином coroutine. thread – является такой функцией. Точки входа\выхода – это функции produce. Каждый раз, когда функция produce вызывается, управление передается “главному” коду, который породил этот поток. В свою очередь вход внутрь потока осуществляется в помощью вызова consume. Но давайте будем последовательными: в 7 строке создается объект Task (зеленый поток или задача) на основе функции thread. Переменная task будет содержать ссылку на поток. Строки 8,9,10 передают управление внутрь потока с помощью метода consume. То, что передается параметром в produce выдается “наружу” потока и выводится с помощью println. Если бы между вызовами функций produce находился какой-то код, то он выполнялся бы до тех пор, пока следующий вызов produce не передал бы управления родительскому коду. Еще, нужно понимать, что в каждый момент времени выполняется только что-то одно. То есть, нет реальной параллельности, что можно наблюдать в современных многопоточных процессорах Intel  или AMD. Это отличие очень важное. Так как оно избавляет нас от всех проблем синхронизации данных. Давайте запустим этот код:

cmdLineRunTask

Этот принцип (псевдопараллелизма) лежит в основе того, как выполняются цифровые организмы в программе jevo. Каждый организм – это поток, выполнение которого прерывается много раз для того, чтобы переключиться внутрь потока другого организма и так далее. Именно это создает видимость многопоточности и параллельного выполнения кода организмов популяции.

Пойду ка я спать… До новых встреч 😉

 

 

 

Advertisements

One thought on “Пост 4. Многозадачная Юля.

  1. Pingback: О чем говорят цифры… | jevo

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s