Особенности Vibe.d

Простота

Модель программирования псевдоблокировки на основе волокн

Основная идея vibe.d заключалась в том, чтобы использовать быструю и ресурсоемкую асинхронную модель ввода-вывода (AIO) и сделать ее удобной в использовании. Некоторые другие программные платформы, такие как node.js, напрямую отображают интерфейс AIO с использованием событий, используя функции обратного вызова. Хотя это приемлемый подход, он имеет ряд недостатков.

Прежде всего, в node.js часто становится утомительным и запутанным писать последовательности кода (например, выполнять несколько последовательных запросов к базе данных). На каждом шаге будет представлен новый callback-вызов (обратный) с новой областью, callback-вызовы ошибок часто приходится обрабатывать отдельно. Это часто является причиной того, что возникает соблазн выполнить слабую обработку ошибок.

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

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

Это делает возможным поддержку для так называемых волокон (также часто называемых совместными подпрограммами). Волокна ведут себя как потоки, просто они фактически работают в одном потоке. Как только бегущее волокно вызывает специальную функцию yield(), она возвращает управление функции, которая запустила волокно. Затем волокно может быть возобновлено в точно таком же положении и с тем же состоянием, которое было у него при вызове yield(). Таким образом, волокна могут мультиплексироваться вместе, выполняться квазипараллельно и максимально использовать каждую емкость нитей.

Все это обычно скрыто за функциями API vibe.d, так что все кажется простой работой с обычными потоками и блокировкой операций. Все блокирующие функции, такие как sleep() или read(), останавливают работу, когда им необходимо ждать, и возобновляют её при возникновении события.

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

Сказав все это, vibe.d может также использоваться без волокон и без цикла обработки событий, если это необходимо, наподобие стандартной блокирующей модели ввода-вывода.

Компактное API

Акцент делается на короткий и простой API. Общие задачи выполняются как можно короче и на высоком уровне, но при этом, при необходимости, допускается низкоуровневый контроль. Используя некоторые из продвинутых функций D, типичные программы на основе vibe.d становятся лаконичными, что обычно могут предложить только скриптовые языки, такие как Ruby.

Нулевое время простоя при изменениях

Встроенный балансировщик нагрузки, способный динамически создавать, запускать и тестировать новые процессы после того, как код был изменен, прежде чем переключать их в главный поток. Это позволяет осуществлять «бесшовные» и с низким уровнем риска изменения в работающих системах.

Обработка ошибок на основе исключений

Обычно обработка исключений ограничивается локальными обработчиками ошибок в средах, основанных на событиях, так как невозможно поместить последовательность событий в блок try-catch, потому что каждая операция создает новую область, когда задействованы обратные вызовы. С другой стороны, vibe.d с его волоконно-ориентированным подходом обладает полной поддержкой обработки исключений.

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

Исключения имеют чрезвычайно полезную функцию, которую едва можно игнорировать. Таким образом, становится гораздо труднее создать трудноотлавливаемые ошибки и дыры в безопасности, непреднамеренно игнорируя условия ошибки. Любые неперехваченные исключения автоматически генерируют страницу ошибок и записывают всю полезную информацию в случае HTTP-сервисов.

Преимущества

Полностью интегрированный веб-фреймворк

Библиотека vibe.d содержит полный набор инструментов, необходимых для разработки веб-сайтов и веб-сервисов. В дополнение к HTTP 1.0/1.1 серверу уже интегрированы статические файлы, эффективная система шаблонов, веб-сокеты, сеансы и другие функции. К числу таких функций относятся фильтр markdown, драйверы MongoDB и Redis, криптография, поддержка JSON и BSON и простой SMTP-клиент.

Есть также средства для автоматической генерации JSON / REST или HTML-интерфейсов на основе форм из классов D, что устраняет много работы и потенциальных ошибок из-за избежания стандартного кода. Генератор интерфейса REST поддерживает генерацию как сервера, так и клиентской части, и как таковой может использоваться как удобный механизм RPC.

Встроенные драйверы баз данных

Основная библиотека содержит встроенную поддержку баз данных MongoDB и Redis. Эти драйверы по умолчанию обеспечивают быстрое и гибкое хранение данных. Дополнительные драйверы базы данных доступны в реестре пакетов DUB, например, совместимый с vibe.d драйвер MySQL.

Совместимость существующих драйверов легко сделать благодаря блокирующей природе API vibe.d. Единственное, что нужно сделать в большинстве случаев – заменить вызовы сокетов (send (), recv (), connect () и т. д.) соответствующими функциями vibe.d. В блоге дается обзор того, что нужно сделать, используя MySQL в качестве примера.

«Сырая» сеть и обработка файлов

Конечно, «сырые» (необработанные) TCP/UDP и доступ к файлам поддерживаются набором инструментальных средств для включения пользовательских протоколов и форматов файлов. I/O происходит через интерфейс блокирующего потока, который эффективно скрывает тот факт, что базовые операции фактически основаны на событиях.

Общие инструменты параллелизма

Помимо операций ввода-вывода поддерживаются все обычные инструменты для общих задач программирования:

  • Sleep() – приостанавливает выполнение текущих задач в течение определенного времени
  • Таймеры позволяют асинхронное планирование обратных вызовов
  • Мьютексы и условные переменные позволяют осуществлять совместный доступ к данным между несколькими потоками без вмешательства в цикл обработки событий
  • Поддержка передачи сообщений
  • Каналы данных для потоковой передачи данных между задачами и потоками

Интеграция графического интерфейса пользователя

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

Для Windows существует собственная реализация драйвера событий (включается с VibeWin32Driver), которая использует функцию MsgWaitForMultipleObjectsEx для обработки оконных сообщений вместе с событиями ввода/вывода или параллелизма. Для систем, работающих под управлением X11, можно использовать createFileDescriptorEvent для прослушивания связи дисплея вместо использования XNextEvent.

Производительность

Асинхронные операции ввода-вывода

Вместо использования классического блокирующего ввода-вывода и многопоточности для выполнения параллельных сетевых и файловых операций все операции используют асинхронные API-интерфейсы операционной системы. По умолчанию libevent используется для доступа к этому API операционной системы независимо.

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

Другим важным аспектом для скорости является то, что, поскольку требуется только один или несколько потоков, часто можно сохранить много дорогих контекстных переключателей потока. Однако, если приложение должно выполнять много вычислений помимо операций ввода-вывода, vibe.d имеет полную поддержку многопоточности, чтобы полностью использовать многоядерный процессор системы.

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

Поддержка многопоточности

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

Помимо разрешения использовать потоков D низкого уровня, предоставляется пул потоков, который используется для любой задачи, запущенной с помощью runWorkerTask вместо runTask. Это в основном полезно для выполнения вычислительно дорогостоящих операций, таких как декодирование изображений, наряду с обычным потоком программ, но оно также может быть использовано для лучшей производительности тяжелых задач ввода-вывода в некоторых случаях.

Библиотека очень гибкая в том, что многопоточность может быть использована, и она гарантирует, что не могут возникнуть условия «низкоуровневых гонок», если не используются небезопасные операции, такие как cast () или __gshared переменные. В следующем списке показаны некоторые типичные архитектуры потоков:

  • Распределенная обработка входящих соединений

HTTP-серверу (а также любому другому серверу на базе TCP) можно поручить обработку входящих соединений по рабочим потокам пула потоков, а не по основному потоку. Для приложений, которым не требуется разделять состояние между различными соединениями в этом процессе, это может увеличить линейное число запросов в секунду по количеству ядер в системе. Эта функция активируется с использованием настроек HTTPServerOption.distribute или TCPListenOptions.distribute.

  • Использование рабочих задач для вычислений

Вычислительные дорогостоящие задачи могут быть выгружены из основного потока, выполнив их с помощью runWorkerTask. Любая такая задача будет выполнена в пуле потоков. Этот подход полезен в тех случаях, когда приложение требует выполнения таких дорогостоящих задач, поскольку оно позволяет чистому выполнению операций ввода-вывода оставаться без изменений при большой вычислительной нагрузке. Вероятно, наиболее распространенным примером такой задачи является обработка/декодирование/кодирование изображений.

  • Использование простых D-потоков

Нормальные потоки D также могут использоваться вместе с vibe.d. Это важно, когда используются потоковые примитивы стандартной библиотеки D. Помимо основных потоков D, это std.parallelism и std.concurrency. Обратите внимание, что части стандартной библиотеки D не следует смешивать с функциями ввода-вывода vibe.d, поскольку они блокируют цикл обработки событий. В частности, функции передачи сообщений в std.concurrency_* в настоящее время несовместимы с циклом событий vibe.d и должны быть заменены функциями vibe.core.concurrency.

Обратите внимание, что vibe.d также включает в себя экспериментальную библиотеку поддерживающую изолированные и ограниченные ссылки. Это позволяет передавать изменяемые данные между потоками без использования мьютексов или аналогичных средств для синхронизации доступа к данным. Это особенно полезно при передаче данных, используемых в рабочих задачах между рабочим потоком и основным потоком.

Встроенный компилятор кода

Vibe.d написан на языке программирования D. D – это C-подобный язык, который компилируется с использованием машинного кода с минимальными затратами времени выполнения. Помимо того, что D является быстрым, D предлагает ряд функций, которые позволяют повысить производительность и улучшить читаемость кода, безопасность и удобство использования по сравнению с другими языками, такими как C ++.

Некоторые заметные отличия перечислены здесь, но есть много дополнительных вещей, которые выходят за рамки этого текста. Смотрите страницу функций D или книгу Programming in D для более тщательного обзора.

  • Шаблоны, миксины и compile-time функции

Метопрограммирование в D чрезвычайно эффективно. Шаблоны (сравнимые с шаблонами C ++) поддерживают параметры variadic, а также параметры строк и параметры-псевдонимы (alias) – это функции, которые обеспечивает очень удобные интерфейсы во время компиляции.

Мощность языка дает возможность выполненять обычные функций во время компиляции, а также возможность компилировать строку, заданную во время компиляции как код D. Эта возможность похожа на функцию eval () в JavaScript: результат статически компилируется в машинный код (и без последствий безопасности eval ()).

Эти функции вместе с возможностью чтения файлов во время компиляции позволили создать мощный синтаксический анализатор шаблонов Diet.

  • Сборщик мусора

Среда выполнения D предлагает встроенную сборку мусора, которая предоставляет некоторые интересные возможности, помимо очевидного преимущества отсутствия необходимости ручного управления памятью и связанного с этим риска утечек памяти и опасных потеряных ссылок.

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

  • Замыкания и лямбда-функции

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

  • Свойства

Свойства – это функции, которые выглядят как поля класса или структуры. Они используются в API для получения логического и интуитивно понятного интерфейса без всякого рода ограничений и дополнительной типизации, необходимой для нормальных вызовов функций.

  • Модульная система
    Модульная система в D похожа на ту, что используется в Java. Среди прочего он семантически прозрачно кодирует зависимости между различными модулями (D-файлами). Используя эту информацию, становится возможным создавать целые приложения, просто указывая корневой файл (app.d) в командной строке. Зависимости можно найти рекурсивно. Инструмент rdmd build, включенный в компилятор D, поддерживаемый менеджером пакетов DUB, работает таким образом.
  • Массивы и срезы

Массивы поддерживают встроенный функциональные возможности выполнения срезов с очень естественным синтаксисом. Совместно со сборщиком мусора они обеспечивают чрезвычайно быструю реализацию синтаксического анализатора строк. Данные операции безопасны (проверяются границы) и легко читаются.

  • Краткий и читаемый синтаксис

Синтаксис в целом очень чистый и по смыслу – особенно в сравнение с его, возможно, самым близким родственником, C ++. Но в этом отношении также не нужно бояться современных скриптовых языков, таких как Ruby и Python. Помимо явной необходимости указывать явный типизации типы могут быть приведены автоматически при помощи оператора auto. Вы обнаружите, что использование auto работает предсказуемо, почти без промахов, и что разработка на D очень эффективна.

Компилируемый шаблонизатор “Diet”

Vibe.d имеет встроенную поддержку HTML-шаблонов Diet на основе синтаксиса шаблона Pug, известного из node.js, который, в свою очередь, основан на Haml. Эти шаблоны устраняют все синтаксические накладные расходы, которые присущи нотации HTML-тегов, а также позволяют вести встроенную спецификацию динамических элементов. Как правило, эти элементы написаны на языке динамических скриптов (JavaScript в случае Pug).
Однако в vibe.d шаблоны могут содержать встроенный код D. Шаблоны читаются и анализируются, пока приложение компилируется и оптимизируется. Для них создается код на D. Это означает, что накладные расходы времени выполнения для этих шаблонов отсутствуют – не осуществляется доступ к диску, не выполняется синтаксический анализ, и нет необходимости в копировании строк, поскольку все это уже будет сделано до того, как приложение будет запущено.
В то же время вы можете программировать на том же языке и остальную часть приложения, что обеспечивает очень последовательную разработку.

Перевод http://vibed.org/features

Компания Двери Белка изготавливает элитные двери для дома с европейскими замками

3 комментария

  1. Вот только если понадобилось изменить шаблон, то придется компилировать все приложение, ну или писать свой шаблонизатор (или использовать таки html).

    1. Да, придётся. Это цена скорости. Встроенный в Vibe.d шаблонизатор diet вообще считаю неудачным решением. Можно посмотреть в сторону temple. В идеале для компилируемых шаблонизаторов было неплохо сделать 2 типа работы: в режиме компиляции и на лету (в режиме разработки). Только это почти в два раза больше работы для разработчиков, так как пришлось бы писать два разных генератора кода.
      В принципе шаблонизаторы, выполняющиеся на лету, работают довольно быстро, так как цель шаблонизаторов в основном лишь вывод инфы. Однако в D таких пока не видел.

Написать ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *