From f0fdfcc0afa6ae982f5713d3d0fcf99d1285db33 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Sat, 8 Oct 2022 00:33:07 +0300 Subject: [PATCH] Crystal Fiber's --- content/posts/2022/crystal/scheduled-func.md | 114 +++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 content/posts/2022/crystal/scheduled-func.md diff --git a/content/posts/2022/crystal/scheduled-func.md b/content/posts/2022/crystal/scheduled-func.md new file mode 100644 index 0000000..66e1d63 --- /dev/null +++ b/content/posts/2022/crystal/scheduled-func.md @@ -0,0 +1,114 @@ +--- +title: "Параллелизм или расписание в Crystal" +date: 2022-10-07T22:43:29+03:00 +draft: false +tags: [crystal, develop, tutorial] +--- + +## Выполнять код раз в 10 секунд? + +Обычная задача в буднях говнокодера. + +Про параллелизм в [Crystal](https://crystal-lang.org/) есть хорошая статья +[Concurrency vs. Parallelism](https://crystal-lang.org/reference/1.6/guides/concurrency.html). + +В целом если её прочитать, то необходимость в прочтении этого руководства отпадает полностью. +Ничего нового ты здесь не узнаешь, однако я продолжу... + +## Глубокий сон + +[sleep](https://crystal-lang.org/api/1.6.0/toplevel.html#sleep%3ANil-class-method) — +Top Level метод, который блокирует текущий `fiber`\* + +\* [Fiber](https://crystal-lang.org/api/1.6.0/Fiber.html) — это исполняемый блок кода, управляемый райнтаймом Crystal. +Концептуально Fiber похож на поток (thread), но с меньшими затратами и полностью внутренне связан с процессом Crystal. +Рантайм включает планировщик, который очевидно планирует выполнение волокон. + +Связь между волокнами обычно осуществляется через [Channel](https://crystal-lang.org/api/1.6.0/Channel.html). + +## Цикличное выполнение + +Для реализации цикла в Crystal можно использовать оператор `while`: + +```crystal +while p! "╭∩╮(Ο_Ο)╭∩╮".class +end +``` + +Или даже оператор `loop`: + +```crystal +loop do + p! "╭∩╮(Ο_Ο)╭∩╮".class +end +``` + +А если запихонить в цикл метод `sleep`, то получим уже имитацию выполнения блока кода +по расписанию: + +```crystal +loop do + p! "╭∩╮(Ο_Ο)╭∩╮".class + + sleep 2 +end +``` + +Но ты же наблюдательный и понял, что пока один loop/while не закончит выполнение, +второй цикл не запустится. + +Вот для таких случаем и нужны Fiber или волокна, просто меня, но я буду называть их `Файберами`. + +## Файберы + +Попробуй запустить этот пример и посмотри что получится. + +```crystal +spawn do + loop do + p! "╭∩╮(Ο_Ο)╭∩╮".class + end +end + +spawn do + loop do + puts Time.local.to_unix + end +end + +sleep +``` + +Тут я создал два файбера, в которых циклично выполняется некий код, +а главный процесс программы я зациклил методом `sleep`. + +Удивительно, не правда ли?) + +Запихониваем в циклы `sleep ` и получаем выполнение каждого файбера с разным интервалом. + +## wrapper + +Всё эту простыню можно оформить таким образом: + +```crystal +def every(period : Time::Span, &block : -> T) forall T + spawn do + loop do + block.call + sleep period + end + end +end + +every(2.seconds) { + puts "-@-@-" +} + +every(4.seconds) { + puts "(-.-)Zzz..." +} + +sleep +``` + +Жрёт это всё ~2Mb памяти.