Введение
мнение автора может не совпадать с вашим мнением, добро пожаловать в комментарии.
В доисторические времена высокопроизводительные Web-приложения можно было писать, в основном, на C или C++. Поддерживать такие приложения было не просто дорого, а очень дорого.
Потребность в среде программирования, в которой удобно писать, читать и изменять высокопроизводительные приложения, появилась давно.
В первую очередь термины "производительность" и "надежность" относятся к Erlang. В своей нише он великолепен, но синтаксис заставляет желать лучшего. Собственно, именно поэтому появился Elixir, но речь сейчас не об этой экосистеме.
Если же немного снизить планку надежности, то здесь перед нами широкий выбор, включая Node, Go, Nim и Crystal. Можно взглянуть на типичные сравнительные данные по производительности, включая более обширные.
Все эти среды программирования предлагают сборщик мусора, что уменьшает сложность поддержки кода.
При это Node предлагает всем понятный язык программирования (и вариации на тему), но динамическая типизация снижает производительность в несколько раз относительно других претендентов.
Если нам нужно больше запросов в секунду, то выбор на сегодня — Go. Эта среда программирования обладает великолепными характеристиками производительности, поддержку со стороны крупных компаний и немалое число активных проектов.
LLVM
Crystal предоставляет фронтэнд для инфраструктуры LLVM, позволяя компилировать код под все поддерживаемые платформы (x64, ARM, Web Assembly etc.).
Статическая типизация без указания типов
Crystal способен в большинстве случаев сам вывести типы используемых данных.
Например, мы где-то отправляем в метод speak в одном случае строку, в другом случае целое число.
В таком случае Crystal на этапе компиляции знает, что метод speak принимает параметр выведенного типа String | Int32.
Мы можем написать такой код:
speak(15)
speak("Whatever")
def speak( thing )
thing.say_every # Ошибка компиляции, у переменной thing тип (Int32 или String), а у него нет метода say_every
# Здесь можно пользоваться методами класса Object, а также всех классов, общих предков String и Int32
if thing.is_a?(String)
# здесь Crystal гарантирует нам, что у переменной thing тип String, и можно пользоваться его методами.
return thing.sub(/\Athe\s+/, "")
elsif thing.responds_to?(:to_s)
# Здесь Crystal гарантирует нам, что у thing есть метод to_s, и его можно вызвать
return thing.to_s
end
end
Важно отметить, что все значения являются объектами, включая числа и строки. Цена всеобъектности — нулевая, ибо операции над объектами определены на этапе статического анализа в компиляторе.
Проверка на пустое значение
В общем случае специальная проверка в коде на пустое значение не требуется. Например, в этом примере попытка передачи пустого значения приведет к ошибке компиляции, так как my_string имеет тип (String или Nil), а у типа Nil нет метода upcase:
if rand(2) > 0
my_string = "hello world"
end
puts my_string.upcase
Модель параллелизма
Crystal поддерживает зеленые потоки, каналы, и опцию SO_REUSEPORT — аналогично Go. В настоящее время идёт работа над качественной поддержкой многопоточности на уровне операционной системы, что приведет к эффективным приложениям на нескольких процессорных ядрах.
Библиотеки
В Crystal фактически встроен свой менеджер зависимостей — Shards.
Функциональность аналогична ruby bundler, perl carton etc. При этом зависимости описываются в shards.yml проекта.
BDD, общий интерфейс по работе с РСУБД и прочие приятности включены в стандартную библиотеку.
Я не стану упоминать различные библиотеки для анализа данных и прочая, для этого есть список Awesome Crystal.
Из того, что не входит в стандартную поставку, но полезно для web-приложений:
Kemal
require "kemal"
# Matches GET "http://host:port/"
get "/" do
"Hello World!"
end
# Creates a WebSocket handler.
# Matches "ws://host:port/socket"
ws "/socket" do |socket|
socket.send "Hello from Kemal!"
end
Kemal.run
crystal-pg
PG_DB.query_one("select ARRAY[1, null, 3]", &.read(Array(Int32?))
# => [1, nil, 3]
PG_DB.query_one("select '{hello, world}'::text[]", &.read(Array(String))
# => ["hello", "world"]
Remarkdown
require "remarkdown"
Remarkdown.to_html("Hello **world**")
Замечания
Надо сказать, что изучил Crystal я на этих выходных, успев выпустить один проект (благодаря сходству синтаксиса с Ruby). И эта статья является точкой зрения новичка в мире Crystal.
Язык пока в процессе реализации, так что большие проекты пока на нём делать не стоит. Версия 1.0 планируется в конце года, но это неточно.
- Пример простой библиотеки: https://github.com/akzhan/luhn.cr.
Комментарии (18)
zolern
10.05.2017 20:27+1Интересные времена настали: резвые новые языки тягаются с дедушками C и C++ и выигрывают. Вот к примеру Crystal (Ruby на стероидах). Или мой любимый Nim (а-ля Python на стероидах) — https://nim-lang.org. Кстати интересно будет сравнение Crystal и Nim (Nim тоже существено быстрее Go).
Как показываеть сравнение CSV Game (https://bitbucket.org/ewanhiggs/csv-game) Nim шустр почти как C, a вот Crystal-я там почему-то нет :)
akzhan
11.05.2017 19:00Можно, думаю, считать похожими по производительности.
Nim — новый статически типизированный язык для LLVM со стороны Python.
- Crystal — новый статически типизированный язык для LLVM со стороны Ruby.
Немного в стороне
- Kotlin — новый статически типизированный язык для JVM со стороны Scala etc.?.
Ph-s
10.05.2017 20:28+3Язык пусть и не стабильный на сей момент (alpha всё таки), но лично у меня вызывает только восторг. И по моим личным ощущениям, он ну очень близок к руби.
Принципиальные отличия от руби — типы всё-таки часто приходится указывать явно, что в случае с кортежами, хешами — порой вынуждает искать другие, более удобные для этого случая подходы. хотя приведение типов имеет и пока не реализованный потенциал.
И вместо метапрограммирования как такового, тут компайл-тайм макросы.
Еще менее стабильны сейчас библиотеки (shards), ибо каждый апдейт языка приносит пачку breaking changes.
Обещают остановиться делать столько ломающих изменений когда достигнут 1.0.
К 1.0 так же торопятся сделать concurency, сейчас же в полной мере реализованы только корутины (fibers) и каналы.
+ достаточно богатая стандартная библиотека.
+ шарды стараются не отставать. даже развиваются фреймворки а-ля синатра (kemal), а-ля рельсы (ametist), + нечто среднее (kemalist, lol). последние два не пробовал.mehatron
10.05.2017 23:58(kemalist, lol)
В какой-то момент подумал, что lol — это название фреймворка. Удивился и даже полез гуглить)
ElectroGuard
11.05.2017 10:26-1Нативный код впереди всей планеты.
Возможно будет кому-то интересно. Веб приложения на Delphi:
unigui
egordeev
11.05.2017 11:02на swift не пробовали писать? Есть фреймворки vapor, kitura, perfect.
есть ещё rust, фреймворк ironPh-s
11.05.2017 11:17Rust все-таки своеобразен и малость хардкорен для веба)
egordeev
11.05.2017 11:54+1rust своеобразен и по сути эту проблему можно решить, если дополнить офф. документацию этого языка бОльшим количеством примеров(особенно сравнительных примеров с другими я.п.);
либо просто можно поискать проекты уже готовые
Alexeyco
Какие критерии надежности применялись для оценки? Чем надежность Java или C# или Python не устроила? Нет, правда, я уважаю Erlang. Но конкретика же.
Alexeyco
Летом 1889 года Антон Палыч Чехов беседовал с неким И. Я. Гурляндом и заявил: «Если вы в первом акте повесили на сцену пистолет, то в последнем он должен выстрелить. Иначе — не вешайте его.» Вот мне интересно, Erlang-то тут к чему был? Так просто?
akzhan
Пока у меня нет готовых проектов на elixir :-)
JC_IIB
А чем конкретно не нравится синтаксис Erlang?
В незапамятные времена человек, учивший меня писать на VoiceXML, сказал отличную фразу — «Тут главное правильно вывернуть мозг». Так и с Erlang — как только мозг выворачивается, внутри что-то щелкает и синтаксис Erlang перестает казаться чем-то необычным. И спустя какое-то время думаешь — хм, а переменные-то и впрямь не нужны. Ох, и без циклов можно обойтись. А еще тут какие-то свертки есть… ну и все такое.
По поводу Elixir я лучше ничего не буду говорить :)
akzhan
Да, C# и Java здесь не затрагивались, мое упущение. Отдельные интересные экосистемы.
Alexeyco
Да просто ничем не подкрепленные утверждения. Что Go — самый быстрый. Автор (то есть, вы) заявляет, но никак ни на что не ссылается. Предполагается, что все написанное — просто догма.
akzhan
В тексте статьи изначально ссылка на одно из сравнений языков по производительности, позднее добавил еще две.
Alexeyco
Надежность. Почему node, go, nim, crystal — супернадежные, а C# и Java даже не были удостоены? Мне нравится пить эту чашу. Ответы-то будут или ограничитесь только минусами?
akzhan
В C# и Java нет супервизоров на уровне VM.
akzhan
На самом деле в статье многое упущено, например, nim. Немного прояснит ситуацию https://github.com/kostya/benchmarks