ECMAScript и все-все-все — различия между версиями
м |
|||
Строка 224: | Строка 224: | ||
</source> | </source> | ||
− | * Ой-ой- | + | * Ой-ой-ой… |
− | * Классов нет, есть процессы | + | * Классов нет, есть процессы. Но сетевой, ага! |
== OCaml O_O @@ == | == OCaml O_O @@ == | ||
Строка 325: | Строка 325: | ||
* Firefox 1.0 | * Firefox 1.0 | ||
* XmlHttpRequest | * XmlHttpRequest | ||
− | * Gmail, впервые упомянут термин «AJAX» | + | * Первое SPA — Gmail, впервые упомянут термин «AJAX» |
* {{gray|Начало конца дремучего периода JS, как языка для всплывающих баннеров}} | * {{gray|Начало конца дремучего периода JS, как языка для всплывающих баннеров}} | ||
Строка 365: | Строка 365: | ||
Потому, что 4-слойный JIT! | Потому, что 4-слойный JIT! | ||
* {{gray|Как уже сказано, интерпретируемых языков нет.}} | * {{gray|Как уже сказано, интерпретируемых языков нет.}} | ||
− | * 1 | + | * 1 слой — LLInt, интерпретатор байткода (быстрый старт) |
− | * 2 | + | * 2 слой — Baseline JIT |
− | * 3 | + | * 3 слой — DFG (Data Flow Graph) JIT |
− | * 4 | + | *: {{gray|здесь появляется типизация}} |
+ | * 4 слой — [https://webkit.org/blog/3362/introducing-the-webkit-ftl-jit/ FTL JIT] (<s>LLVM</s> [https://webkit.org/blog/5852/introducing-the-b3-jit-compiler/ B3]) | ||
https://webkit.org/blog-files/ftl-jit/four_tier_performance.png | https://webkit.org/blog-files/ftl-jit/four_tier_performance.png | ||
Строка 391: | Строка 392: | ||
== LLVM @@ == | == LLVM @@ == | ||
− | LLVM (http://llvm.org), ранее | + | LLVM (http://llvm.org), ранее «Low Level Virtual Machine» |
* Набор библиотек для построения компиляторов/интерпретаторов | * Набор библиотек для построения компиляторов/интерпретаторов | ||
* Модульный | * Модульный | ||
Строка 428: | Строка 429: | ||
== V8 JIT @@ == | == V8 JIT @@ == | ||
− | |||
* Первый раз функции запускаются в LLInt | * Первый раз функции запускаются в LLInt | ||
* 6 вызовов либо 100 повторов строки | * 6 вызовов либо 100 повторов строки | ||
*: {{green|→ OSR в Baseline JIT}} | *: {{green|→ OSR в Baseline JIT}} | ||
− | * 66 вызовов либо | + | * C*66 вызовов либо C*1000 повторов строки |
*: {{green|→ OSR в DFG JIT}} | *: {{green|→ OSR в DFG JIT}} | ||
*: C ~ 1, больше для больших функций | *: C ~ 1, больше для больших функций | ||
* Нарушение type guard в DFG | * Нарушение type guard в DFG | ||
*: {{red|→ OSR обратно в Baseline JIT}} | *: {{red|→ OSR обратно в Baseline JIT}} | ||
− | * 6666 вызовов либо | + | * C*6666 вызовов либо C*100000 повторов строки |
*: {{green|→ OSR в LLVM/B3 JIT}} | *: {{green|→ OSR в LLVM/B3 JIT}} | ||
+ | |||
+ | == Производительность @@ == | ||
+ | |||
+ | * Итого, V8 — «смешанный» JIT | ||
+ | * В Firefox — [https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/Tracing_JIT тоже всё шустро] | ||
+ | * Чакра Наделлы тоже очень похожа на V8 | ||
+ | * Постоянная битва :) https://arewefastyet.com/ | ||
+ | * {{red|Но язык - ещё не всё!}} Ещё есть: | ||
+ | *: В браузере — {{green|DOM}} (медленный в старых Firefox при формально быстром JS) | ||
+ | *: На сервере — {{green|ввод/вывод}} | ||
+ | |||
+ | == I/O bound, а не CPU bound @@ == | ||
+ | |||
+ | * Типичные веб- и бизнес- приложения {{mag|сетевые}} | ||
+ | *: ''«получить из одного места (базы, кэша) и переложить в другое / отдать клиенту»'' | ||
+ | *: {{gray|nb: все наши веб-фреймворки ни фига не делают :)}} | ||
+ | *: {{gray|nb: иначе PHP-сайтики были бы неюзабельны}} | ||
+ | * Иногда — '''очень сетевые''' (C10K / C1M) | ||
+ | *: чисто русский термин «хайлоад» | ||
+ | *: 10gbit ethernet уже среди нас | ||
+ | |||
+ | <big>⇒ ?..</big> | ||
+ | |||
+ | == Событийные машины! @@ %% == | ||
+ | |||
+ | {{gray|("event loop")}} | ||
+ | |||
+ | == Как вообще обрабатываются соединения клиентов? @@ == | ||
+ | |||
+ | {{green|Все писали сетевой сервер на C? :)}} | ||
+ | |||
+ | {{red|Обычный ('''блокирующий''') ввод/вывод:}} | ||
+ | * forking: socket(), accept(), fork(), дочерний процесс работает с клиентом | ||
+ | * threading: socket(), accept(), создаём поток, дочерний работает с клиентом | ||
+ | * prefork / thread pool: создаём N процессов/потоков заранее | ||
+ | * Потоки и процессы — объекты ОС | ||
+ | *: {{gray|разница, по сути, только в наличии/отсутствии изоляции памяти}} | ||
+ | *: Переключение контекста CPU — тяжёлая операция | ||
+ | *: 100 потоков — уже тяжело | ||
+ | *: ''«Проблема C10K» (обработать 10000 соединений на 1 сервере)'' | ||
+ | |||
+ | == Событийная машина @@ == | ||
+ | |||
+ | {{green|Неблокирующий ввод/вывод:}} | ||
+ | * socket() | ||
+ | * select() / poll() / epoll / kqueue | ||
+ | *: говорим ОС: «разбуди, когда в любом из сокетов что-то произойдёт» | ||
+ | *: сокет пока один (слушающий) | ||
+ | * новое соединение => добавляем в select и спим дальше | ||
+ | * кто-то прислал запрос => читаем, быстро обрабатываем, отвечаем, спим дальше | ||
+ | * '''всё в один поток''' {{gray|(или в несколько по числу ядер CPU)}} | ||
+ | |||
+ | == Так работает Nginx… @@ %% == | ||
+ | |||
+ | …и весь современный Web (фронтенды) | ||
+ | |||
+ | [[Файл:Nginx-logo.png]] | ||
+ | |||
+ | {{gray|(плюс zero-copy и раздача статики через sendfile())}} | ||
+ | |||
+ | == А если пойти дальше? @@ == | ||
+ | |||
+ | Кроме HTTP-запросов клиентов ещё есть: | ||
+ | * СУБД/кэши | ||
+ | * Файлы | ||
+ | * REST сервисы | ||
+ | * Websocket’ы | ||
+ | * Сетевые серверы (IMAP?) | ||
+ | |||
+ | Почему бы всё это не обрабатывать в одном цикле? | ||
+ | |||
+ | {{mag|⇒ Это и будет «событийная машина»}} | ||
+ | |||
+ | == Событийные машины @@ == | ||
+ | |||
+ | Почти везде опциональная сущность: | ||
+ | * Python: [https://twistedmatrix.com/ Twisted] | ||
+ | *: более-менее популярен | ||
+ | * Java: [http://vertx.io/ Vert.x], [https://github.com/webbit/webbit Webbit] | ||
+ | *: {{gray|мало кто использует, ынтырпрайз же, а тут хипстота какая-то}} | ||
+ | *: в JEE потоки во все поля | ||
+ | *: да, внутри wildfly тоже event loop — но только для | ||
+ | * PHP: [https://github.com/kakserpom/phpdaemon kak.serpom.po.yaitsam/phpdaemon] | ||
+ | *: {{gray|почти никто не использует}} | ||
+ | * Механизмы разные в разных ОС ⇒ '''libevent''', '''libev''' | ||
+ | |||
+ | == Событийная машина node.js @@ == | ||
+ | |||
+ | * Отличительная черта: '''вообще нет блокирующего I/O''' | ||
+ | *: {{gray|тут-то колбэки JS и становятся преимуществом}} | ||
+ | * Реально работает: [https://habrahabr.ru/post/123154/ тест 1M соединений на 1 сервере] | ||
+ | * Кроме {{green|node.js}} такое есть только в {{mag|Erlang}} | ||
+ | *: и, кстати, успешно переваривает 1M соединений, причём '''на продакшне''' (у WhatsApp) | ||
+ | *: {{gray|но... erlang. и медленный он по сравнению с V8}} | ||
[[Категория:VitaliPrivate]] | [[Категория:VitaliPrivate]] |
Версия 16:37, 10 октября 2016
- Автор
- Виталий Филиппов
- Дополнительный нижний колонтитул
- ECMAScript и все-все-все
Содержание
- 1 ECMAScript — ассемблер будущего, бэкенд, фронтенд и все-все-все @@ %%
- 2 О своих предпочтениях @@
- 3 О чём доклад? @@
- 4 Что такое JS? @@
- 5 Скриптота vs типизация @@ %%
- 6 Холивар!!! @@
- 7 Все хотят одного @@
- 8 Проверки — хорошо, но @@ %%
- 9 Почему JS? @@
- 10 Синтаксис @@ %%
- 11 Perl @@
- 12 PHP @@
- 13 Python @@
- 14 Ruby @@
- 15 Go @@
- 16 Erlang @@
- 17 OCaml O_O @@
- 18 JS @@
- 19 Синтаксис JS @@ %%
- 20 История JS @@
- 21 Дремучий период @@
- 22 Появление AJAX @@
- 23 Современное развитие @@
- 24 Производительность @@
- 25 Вычислительный бенчмарк @@
- 26 Почему V8 такой быстрый? @@
- 27 Ключевые слова о том, как это всё устроено @@
- 28 Отступление: PyPy @@ %%
- 29 LLVM @@
- 30 SSA @@
- 31 V8 JIT @@
- 32 Производительность @@
- 33 I/O bound, а не CPU bound @@
- 34 Событийные машины! @@ %%
- 35 Как вообще обрабатываются соединения клиентов? @@
- 36 Событийная машина @@
- 37 Так работает Nginx… @@ %%
- 38 А если пойти дальше? @@
- 39 Событийные машины @@
- 40 Событийная машина node.js @@
ECMAScript — ассемблер будущего,
бэкенд, фронтенд и все-все-все @@ %%
(Об эволюции и фичах JavaScript)
Виталий Филиппов, CUSTIS
О своих предпочтениях @@
«И давно вы занимаетесь программизмом?»
- Начинал лет в 11 с C/C++ (Turbo C / C++Builder)
- Потом открыл для себя Linux, свободный софт…
- главное читать логи :)
- …LAMP (Perl/PHP), HTML и JS
- Теперь полюбил серверный JS (nodejs)
О чём доклад? @@
- Почему JS?
- История JavaScript
- Обзор языка, производительность
- Обзор выдумок
- (фреймворки, системы сборки и т.п)
- Немного демо
Что такое JS? @@
JavaScriptECMAScript
- От Java только часть названия
- Скриптота! (динамический язык)
- Объект/массив/скаляр (JSON)
- Прототипы, замыкания, колбэки, нет многопоточности
- ES — язык. А ещё есть окружение (DOM, BOM)
- Куча новых фич (ES2015-2016-2017)
- Браузерный — Chrome (V8), Firefox (SpiderMonkey) и даже IE (ChakraCore)
- Серверный — node.js (V8)
Скриптота vs типизация @@ %%
Холивар!!! @@
- Шутки в сторону: тема серьёзная
- Популярных динамических языков много
- можно пытаться это отрицать, но таки удобно
- Статические… хде они? Java? (C# не в счёт, винда)
- Компилируемые новые есть: D, Rust, Go, Vala, Swift
- но кто на них пишет-то?
Все хотят одного @@
- Типизация — не необходимость, как раньше, а лишь один из способов проверки
- что ещё можно проверять?
- Rust = borrow checker
- функциональщина = «purity» checker
- При этом
- auto уже даже в C++
- тайпчекер (частично) уже даже в PHP (+ Hack)
Проверки — хорошо, но @@ %%
Почему JS? @@
- Нейтральный C-подобный синтаксис
- Быстрый! (как вычислительно, так и для I/O)
- Событийная машина node.js — не пустой звук! (1M соединений на одном сервере)
- Всегда нужен в браузерах (а веб нынче даже 1С)
- Мощное сообщество и развитие
- Удобный пакетный менеджер npm
- Есть тайпчекеры: TypeScript, Dart…
Синтаксис @@ %%
Perl @@
sub _skip_attrs { my ($tag, $attrs) = @_; $tag = lc $tag; return "<$tag>" if $tag =~ m!^/!so; my ($enclosed) = $attrs =~ m!/$!so ? ' /' : ''; $attrs = { $attrs =~ /([^\s=]+)=([^\s=\'\"]+|\"[^\"]*\"|\'[^\']*\')/gso }; my $new = {}; for (qw(name id class style title)) { $new->{$_} = $attrs->{$_} if $attrs->{$_}; } my %l = (a => 'href', blockquote => 'cite', q => 'cite'); if ($attrs->{$l{$tag}} && $attrs->{$l{$tag}} !~ /^[\"\']?javascript/iso) { $new->{$l{$tag}} = $attrs->{$l{$tag}}; } return "<$tag".join("", map { " $_=".$new->{$_} } keys %$new).$enclosed.">"; }
- Спецсимволы захватили мир
PHP @@
$isExact = []; foreach ([ 'line' => 'l', 'cfo' => 'cc' ] as $k => $t) { if (!isset($specified[$k.'_id']) && !isset($specified[$k.'_id_exact']) && !isset($groups[$k]) && !isset($groups[$k.'_all'])) $isExact[] = "$posAlias.${k}_id IS NULL"; elseif ($lastgrp == $k.'all') $isExact[] = "$posAlias.${k}_id=$t.id"; } foreach ([ 'party', 'account', 'paytype' ] as $k) if (!isset($specified[$k.'_id']) && !isset($groups[$k])) $isExact[] = "$posAlias.${k}_id IS NULL"; return implode(' AND ', $isExact) ?: '1=1';
- Что за $$$$$?
Python @@
class FileCache: def __init__(self, dir): self.dir = dir if not os.path.isdir(dir): os.mkdir(dir) def fn(self, key): key = re.sub('([^a-zA-Z0-9_\-]+)', lambda x: binascii.hexlify(x.group(1)), key) return self.dir+'/'+key def clean(self): t = time.time() for fn in os.listdir(self.dir): if t > os.stat(self.dir+'/'+fn).st_mtime: os.unlink(self.dir+'/'+fn)
- Пробелы меняют смысл?!!!!
Ruby @@
module Gitlab class SearchResults attr_reader :current_user, :query def objects(scope, page = nil) case scope when 'projects' projects.page(page).per(per_page) when 'issues' issues.page(page).per(per_page) when 'merge_requests' merge_requests.page(page).per(per_page) when 'milestones' milestones.page(page).per(per_page) else Kaminari.paginate_array([]).page(page).per(per_page) end end
- projects — переменная? Фигвам. Метод без аргументов.)
Go @@
func TestChannelStoreSave(t *testing.T) { Setup() teamId := model.NewId() o1 := model.Channel{} o1.TeamId = teamId o1.DisplayName = "Name" o1.Name = "a" + model.NewId() + "b" o1.Type = model.CHANNEL_OPEN if err := (<-store.Channel().Save(&o1)).Err; err != nil { t.Fatal("couldn't save item", err) } if err := (<-store.Channel().Save(&o1)).Err; err == nil { t.Fatal("shouldn't be able to update from save") }
- Что за смайлики := <- & *? Где мои скобочки?
Erlang @@
iq_handler(From, _To, #iq{type=set, lang = Lang, sub_el = #xmlel{name = Operation} = SubEl} = IQ, CC)-> ?DEBUG("carbons IQ received: ~p", [IQ]), {U, S, R} = jid:tolower(From), Result = case Operation of <<"enable">>-> ?INFO_MSG("carbons enabled for user ~s@~s/~s", [U,S,R]), enable(S,U,R,CC); <<"disable">>-> ?INFO_MSG("carbons disabled for user ~s@~s/~s", [U,S,R]), disable(S, U, R) end, case Result of ok -> ?DEBUG("carbons IQ result: ok", []), IQ#iq{type=result, sub_el=[]}; {error,_Error} -> ?ERROR_MSG("Error enabling / disabling carbons: ~p", [Result]), Txt = <<"Database failure">>, IQ#iq{type=error,sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]} end;
- Ой-ой-ой…
- Классов нет, есть процессы. Но сетевой, ага!
OCaml O_O @@
let log_client_info c sock = let buf = Buffer.create 100 in let date = BasicSocket.date_of_int (last_time ()) in Printf.bprintf buf "%-12s(%d):%d -> %-30s[%-14s %-20s] connected for %5d secs %-10s bw %5d/%-5d %-6s %2d/%-2d reqs " (Date.simple date) (nb_sockets ()) (client_num c) ( let s = c.client_name in let len = String.length s in if len > 30 then String.sub s 0 30 else s) (brand_to_string c.client_brand) (match c.client_kind with Indirect_address _ | Invalid_address _ -> "LowID" | Direct_address (ip,port) -> Printf.sprintf "%s:%d" (Ip.to_string ip) port) (last_time () - c.client_connect_time) (if c.client_rank > 0 then Printf.sprintf "rank %d" c.client_rank else "") (nwritten sock) (nread sock) (if c.client_banned then "banned" else "") c.client_requests_received c.client_requests_sent ;
- ПОЛИЗ?!!!!
JS @@
TreeGridNode.prototype.setChildren = function(isLeaf, newChildren) { if (!this.tr) this.grid.tbody.innerHTML = ''; else { var tr = this.tr[this.tr.length-1]; while (tr.nextSibling && tr.nextSibling._node.level > this.level) this.grid.tbody.removeChild(tr.nextSibling); if (this.leaf != isLeaf) { if (isLeaf) { this.tr[0].cells[0].firstChild.className = 'collapser collapser-inactive'; removeListener(this.tr[0].cells[0].firstChild, 'click', this._getToggleHandler()); } else { this.tr[0].cells[0].firstChild.className = this.collapsed ? 'collapser collapser-collapsed' : 'collapser collapser-expanded'; addListener(this.tr[0].cells[0].firstChild, 'click', this._getToggleHandler()); } } } this.leaf = isLeaf; this.children = []; this.childrenByKey = {}; this.addChildren(newChildren); }
Синтаксис JS @@ %%
Имхо вполне нейтральненько.
(неприятных рефлексов вызывать не должен)
История JS @@
- 1995—2004: дремучий лес с партизанами
- 2004—2008: появление AJAX
- 2008+: шустрота и современный период
Дремучий период @@
1995—1997
- Создание и начальная стандартизация
- DOM ещё нет, только «DOM level 0»
- document.forms, document.images
1998
- DOM level 1 (DHTML)
- document.getElementById, все элементы — объекты
2000
- DOM level 2
- События и более-менее современный вид объектов
- pre-AJAX: JSONP, невидимый iframe
Появление AJAX @@
2004
- Firefox 1.0
- XmlHttpRequest
- Первое SPA — Gmail, впервые упомянут термин «AJAX»
- Начало конца дремучего периода JS, как языка для всплывающих баннеров
Совместимость браузеров ещё плохая, так что
- 2006 — jQuery
Современное развитие @@
- 2008 — Google V8
- 2009 — IE8 (M$ очнулся)
- 2009 — node.js (2011 — v0.6)
- 2011 — начало работы над ES6
- 2012 — Angular 1.0
- 2013 — React
- 2015 — ES6 принят
Производительность @@
На ЛОРе до сих пор шутят, что «Java тормозит», а что ж тогда JS?
- А ничего — он быстрый.
- Но он же интерпретируемый?
- НЕТ! Интерпретируемых языков уже вообще нет.
- Ну, разве что bash…
Вычислительный бенчмарк @@
- C++ (g++ 5.3.1) -O2 = 1.124s
- java8 = 1.428s
- PyPy (tracing jit) = 1.72s
- node.js = 2s
- java7 = ~2.5s
- PHP 7 = 6.7s
- Python 3.5 = 19s, 2.7 = 21s
- Perl = 25s
- PHP 5.6 = 69s :)))))
Почему V8 такой быстрый? @@
Потому, что 4-слойный JIT!
- Как уже сказано, интерпретируемых языков нет.
- 1 слой — LLInt, интерпретатор байткода (быстрый старт)
- 2 слой — Baseline JIT
- 3 слой — DFG (Data Flow Graph) JIT
- здесь появляется типизация
- 4 слой — FTL JIT (
LLVMB3)
Ключевые слова о том, как это всё устроено @@
- Какой бывает JIT?
- method-based jit (JVM)
- tracing jit (PyPy, TraceMonkey)
- Девиртуализация
- Ускорение поиска в хеше (Lua)
- OSR (On-Stack Replace)
Отступление: PyPy @@ %%
Трассирующий JIT-компилятор для Python, очень медленный
Рисует множество Мандельброта при сборке
LLVM @@
LLVM (http://llvm.org), ранее «Low Level Virtual Machine»
- Набор библиотек для построения компиляторов/интерпретаторов
- Модульный
- исходник → фронтенд (ЯП) → LLVM IR (SSA)
- IR → оптимизатор LLVM → IR
- IR → бэкенд → машинный код
- А также сами компиляторы (в первую очередь C/C++/ObjC: Clang)
- На LLVM сделаны компилятор шейдеров Radeon и OpenCL
SSA @@
Пример LLVM IR:
store i32 1, i32* %e, align 4 br label %4 ; <label>:4 ; preds = %29, %0 %5 = load i32* %a, align 4 %6 = load i32* %b, align 4 %7 = add nsw i32 %5, %6 store i32 %7, i32* %c, align 4 %8 = load i32* %c, align 4 %9 = load i32* %a, align 4 %10 = sub nsw i32 %8, %9 store i32 %10, i32* %d, align 4 %11 = load i32* %d, align 4 %12 = icmp ne i32 %11, 0 br i1 %12, label %13, label %14 ; <label>:13 ; preds = %4 br label %20
V8 JIT @@
- Первый раз функции запускаются в LLInt
- 6 вызовов либо 100 повторов строки
- → OSR в Baseline JIT
- C*66 вызовов либо C*1000 повторов строки
- → OSR в DFG JIT
- C ~ 1, больше для больших функций
- Нарушение type guard в DFG
- → OSR обратно в Baseline JIT
- C*6666 вызовов либо C*100000 повторов строки
- → OSR в LLVM/B3 JIT
Производительность @@
- Итого, V8 — «смешанный» JIT
- В Firefox — тоже всё шустро
- Чакра Наделлы тоже очень похожа на V8
- Постоянная битва :) https://arewefastyet.com/
- Но язык - ещё не всё! Ещё есть:
- В браузере — DOM (медленный в старых Firefox при формально быстром JS)
- На сервере — ввод/вывод
I/O bound, а не CPU bound @@
- Типичные веб- и бизнес- приложения сетевые
- «получить из одного места (базы, кэша) и переложить в другое / отдать клиенту»
- nb: все наши веб-фреймворки ни фига не делают :)
- nb: иначе PHP-сайтики были бы неюзабельны
- Иногда — очень сетевые (C10K / C1M)
- чисто русский термин «хайлоад»
- 10gbit ethernet уже среди нас
⇒ ?..
Событийные машины! @@ %%
("event loop")
Как вообще обрабатываются соединения клиентов? @@
Все писали сетевой сервер на C? :)
Обычный (блокирующий) ввод/вывод:
- forking: socket(), accept(), fork(), дочерний процесс работает с клиентом
- threading: socket(), accept(), создаём поток, дочерний работает с клиентом
- prefork / thread pool: создаём N процессов/потоков заранее
- Потоки и процессы — объекты ОС
- разница, по сути, только в наличии/отсутствии изоляции памяти
- Переключение контекста CPU — тяжёлая операция
- 100 потоков — уже тяжело
- «Проблема C10K» (обработать 10000 соединений на 1 сервере)
Событийная машина @@
Неблокирующий ввод/вывод:
- socket()
- select() / poll() / epoll / kqueue
- говорим ОС: «разбуди, когда в любом из сокетов что-то произойдёт»
- сокет пока один (слушающий)
- новое соединение => добавляем в select и спим дальше
- кто-то прислал запрос => читаем, быстро обрабатываем, отвечаем, спим дальше
- всё в один поток (или в несколько по числу ядер CPU)
Так работает Nginx… @@ %%
…и весь современный Web (фронтенды)
(плюс zero-copy и раздача статики через sendfile())
А если пойти дальше? @@
Кроме HTTP-запросов клиентов ещё есть:
- СУБД/кэши
- Файлы
- REST сервисы
- Websocket’ы
- Сетевые серверы (IMAP?)
Почему бы всё это не обрабатывать в одном цикле?
⇒ Это и будет «событийная машина»
Событийные машины @@
Почти везде опциональная сущность:
- Python: Twisted
- более-менее популярен
- Java: Vert.x, Webbit
- мало кто использует, ынтырпрайз же, а тут хипстота какая-то
- в JEE потоки во все поля
- да, внутри wildfly тоже event loop — но только для
- PHP: kak.serpom.po.yaitsam/phpdaemon
- почти никто не использует
- Механизмы разные в разных ОС ⇒ libevent, libev
Событийная машина node.js @@
- Отличительная черта: вообще нет блокирующего I/O
- тут-то колбэки JS и становятся преимуществом
- Реально работает: тест 1M соединений на 1 сервере
- Кроме node.js такое есть только в Erlang
- и, кстати, успешно переваривает 1M соединений, причём на продакшне (у WhatsApp)
- но... erlang. и медленный он по сравнению с V8