Comments 36
Да, вы правы. В этой статье HashMap используется намеренно, для упрощения примеров и для того, чтобы оставить поле для дальнейшей оптимизации, которая будет описана в одной из следующих частей. :)
0
Полез в оригинал — там тоже есть замечание про slab с комментарием автора в духе «неосилил» :-)
+2
Каюсь, неосиливший автор оригинала — это тоже я. :)
+5
Блин, так глубоко я не залез! Тогда рассказываю: размер slab задается один раз и не меняется, т.е. этим размером и лимитируется количество подключений, но зато получение нового слота в slab очень быстрое. В данном случае нужен
На линуксе по умолчанию:
Slab::new_starting_at()
со сдвигом 1, т.к. токен 0 уже занят для входящего сокета.На линуксе по умолчанию:
net.core.somaxconn = 128
, насколько я помню, традиционно размер slab ставят эквивалентным беклогу.+1
Проблема в том, что Вебсокетный сервер может держать множество висящих подключений — см., например, проблему C10K. Но думаю, что это должно решаться аллокацией новых slab'ов при «исчерпании» старых — только это усложняет код, поэтому в примерах и используется HashMap.
Короче говоря, нужно все досконально тестировать и запускать микробенчмарки — не хотелось с самого начала смещать фокус статьи на такие суровые детали реализации.
Короче говоря, нужно все досконально тестировать и запускать микробенчмарки — не хотелось с самого начала смещать фокус статьи на такие суровые детали реализации.
0
Спасибо за статью! mio выглядит довольно интересно. С ней, кстати, работают такие библиотеки как mioco и coio-rs, которые дают чуть более высокоуровневый интерфейс. Может быть, их тоже возможно как-то применить в вашем случае?
Пара небольших замечаний: в функцию gen_key лучше передавать &str, а не &String — &String вообще никогда не имеет смысла использовать, а конструкцию типа
Пара небольших замечаний: в функцию gen_key лучше передавать &str, а не &String — &String вообще никогда не имеет смысла использовать, а конструкцию типа
"abcde".as_bytes()
можно заменить на b"abcde"
.0
Тогда уже
AsRef<str>
можно сразу.0
Я сам точно не уверен, когда AsRef нужно применять, но точно знаю, что &str однозначно идиоматичнее &String. В данном случае AsRef, имхо, это перебор.
+2
В
Так что его стоит применять там где на входе может быть
std
есть две реализации:
impl AsRef<str> for str
impl AsRef<str> for String
Так что его стоит применять там где на входе может быть
&str
или String
, а используется только &str
.0
Да, но в подавляющем большинстве случаев если вы используете только &str, то разрешать передавать String нет никакого смысла — в этом случае произойдёт передача права владения, которая совершенно бессмысленна, если используется только &str. Поэтому я и говорю, что я не вижу смысла в AsRef.
+1
Спасибо! Насчет String, вы, конечно, правы — я еще не до конца освоился в Rust на момент написания статьи.
Есть еще проект Rotor, мне понравился его подход к композиции протоколов внутри mio — я подумаю над тем, как его можно будет использовать для следующих частей статьи.
Может быть, их тоже возможно как-то применить в вашем случае?Да, звучит интересно — но так или иначе, в дальнейшем предполагается выстраивать собственный высокоуровневый интерфейс для работы с Вебсокетами.
Есть еще проект Rotor, мне понравился его подход к композиции протоколов внутри mio — я подумаю над тем, как его можно будет использовать для следующих частей статьи.
-1
А mio умеет масштабироваться по ядрам?
0
Да, умеет — ничего особо в этом ему мешать не должно.
Рассмотрение многопоточных циклов событий в планах на следующие части. Следите за обновлениями. :)
Рассмотрение многопоточных циклов событий в планах на следующие части. Следите за обновлениями. :)
0
Таки нет, сам не умеет:
Что означает, что это нужно делать самому, либо искать более высокоуровневую обертку, в которой это реализовано.
The following are specifically omitted from MIO and are left to the user or higher level libraries.
File operations
Thread pools / multi-threaded event loop
Что означает, что это нужно делать самому, либо искать более высокоуровневую обертку, в которой это реализовано.
0
ничто не мешает форкнуться на N-процессов перед запуском mio event loop.
0
Ничто не мешает. Как ничто не мешает запустить несколько потоков, в каждом запустить event loop, и диспетчеризировать подключения между ними в рамках одного процесса. Но сам mio ни того, ни другого не делает, и в планы его развития это не входит.
+1
запустить несколько потоков, в каждом запустить event loop, и диспетчеризировать подключения между ними в рамках одного процессаНу, на самом деле я именно так и планировал сделать и рассказать об этом в одной из следующих статей.
Полагаю, что вопрос cy-ernado касается самой теоретической возможности разброса event loop'ов на несколько ядер/процессоров — а с этой точки зрения, конечно, mio все умеет. :)
0
TcpSocket убрали из публичного API: github.com/carllerche/mio/pull/262
Можно зависеть не на мастер, а на 0.4, тогда почти работает
Можно зависеть не на мастер, а на 0.4, тогда почти работает
+1
Точно, спасибо! Лучше переделаю на использование стандартного класса mio, TcpListener.
0
В начале главы 7, видимо, нужен register вместо register_opt ;) у меня компилятор ругается:
src/main.rs:25:16: 28:41 error: no method named `register_opt` found for type `mio::event_loop::EventLoop<_>` in the current scope
src/main.rs:25 event_loop.register_opt(&server_socket,
src/main.rs:26 Token(0),
src/main.rs:27 EventSet::readable(),
src/main.rs:28 PollOpt::edge()).unwrap();
+1
UFO just landed and posted this here
Я думаю что поддержка Windows в mio пока еще очень сырая. Но вообще для подобных вопросов у них существует канал в IRC — irc.mozilla.org/#mio.
Ну и, честно говоря, Windows при написании статьи я вообще не учитывал. Наверное, это плохо, но из моей практики серверы под Win — исчезающе редкое явление. Я бы на вашем месте экспериментировал в виртуальной машине с Linux'ом.
Ну и, честно говоря, Windows при написании статьи я вообще не учитывал. Наверное, это плохо, но из моей практики серверы под Win — исчезающе редкое явление. Я бы на вашем месте экспериментировал в виртуальной машине с Linux'ом.
0
UFO just landed and posted this here
"в современных серверных процессорах обычно есть от 8 до 16 ядер, и если мы создаем больше потоков, чем позволяет “железо”, то планировщик ОС перестает справляться с переключением задач с достаточной скоростью."
Я бы поспорил. В 2007-м на машине с 4 ядрами мы гоняли систему с 8000 (восемью тысячами) нитей. Именно в обслуживании http-запросов. Правда, потребовался тюнинг настроек ядра и стандартную jvm заменили на, ЕМНИП, jrockit.
Я бы поспорил. В 2007-м на машине с 4 ядрами мы гоняли систему с 8000 (восемью тысячами) нитей. Именно в обслуживании http-запросов. Правда, потребовался тюнинг настроек ядра и стандартную jvm заменили на, ЕМНИП, jrockit.
+2
Не спорю, конструкция фразы не совсем удачная — подразумевалось скорее значительно превышающее разумные пределы кол-во тредов.
В этом плане 8000 — относительно небольшое число, потому что известная "проблема C10K" уже в далеком прошлом. Как себя в тех же условиях покажут, скажем, 100 тысяч потоков? А миллион? А 10 миллионов? :) Это более актуальные на сегодняшний день цифры.
В этом плане 8000 — относительно небольшое число, потому что известная "проблема C10K" уже в далеком прошлом. Как себя в тех же условиях покажут, скажем, 100 тысяч потоков? А миллион? А 10 миллионов? :) Это более актуальные на сегодняшний день цифры.
0
А реально ли актуальные? Миллион активных соединений вряд ли отработает сам сервер. Миллиону неактивных, казалось бы, неоткуда взяться… Конечно, по сути, нельзя ограничиваться просто числом и надо описывать распределение — скорость поступления запросов (в секунду), и распределение запросов по шкале стоимости — столько процентов висят без обслуживания, столько обслуживаются коротко (Out of memory), столько — обслуживаются дорого.
+1
Поднять можно многое, но в реальности же за соединением — бизнес-логика. По опыту, упираемся не в соединения, не в треды, а в производительность бизнес-логики.
+1
Sign up to leave a comment.
Rust в деталях: пишем масштабируемый чат с нуля, часть 1