Почему в Rust использую Tokio?
Я не могу понять популярность Tokio. Стандартная библиотека Rust написана очень хорошо: она реализует весь необходимый функционал, работает гораздо быстрее Tokio. Я видел немного проектов, которые использовали бы стандартную библиотеку, большинство проектов, что я видел, такие как веб-серверы или коннекторы к СУБД написаны поверх Tokio. У Tokio более 24 тысяч звёзд на Github и она используется почти везде (даже в приложениях вроде Discord или Amazon). Но почему используют Tokio, а не стандартную библиотеку?
Дополнительно:
Потому что она реализует то, чего нет в стандартной библиотеке - асинхронный рантайм. Если писать сетевое приложение без токио, то придется плодить по отдельному потоку на каждый сетевой коннекшен. (на самом деле, речь идет про любой i/o, к которому чтение/запись файлов тоже относится) Каждый из этих потоков большую часть времени будет заблокирован в ожидании завершения сететвого вызова (передачи или приема данных). Однако, операционная система при разблокировке этих тредов будет постоянно переключать контекст для каждого потока и тратить процессорное время.
Асинхронный подход позволяет обойтись лишь сравнительно небольшим пулом потоков, на которые токио рантайм будет распределять таски (грин треды) и, таким образом, экономить процессорное время.
- D3lphi,
экономить процессорное время.
На моих тестах (как и на тех, что я находил в сети) единственное что Tokio делает лучше с точки зрения производительности - это сон. Спит Tokio действительно гораздо дешевле. Если рассмотреть стандартную библиотеку, то она работает далеко не всегда синхронно. Иногда она "паркует" потоки и "будит" их только в момент готовности. Мои тесты подтверждают это теорию.
Однако я мог не рассмотреть нужный случай. Если есть ещё какой-нибудь тест, где Tokio показывает себя лучше, опишите его. Я проведу его в свободное время.
- Eugene Usachev,
Иногда она "паркует" потоки и "будит" их только в момент готовности. Мои тесты подтверждают это теорию.
А теперь попробуй без tokio реализовать сервер, который сможет работать с 10к открытых соединений.
Ну или клиент, который эти 10к одновременных запросов совершит.
Даже спящие потоки не бесплатные и ОС тратит на них ресурсы.
10к новых потоков на уровне ОС - это жёстко.
10к тасок в tokio - чих. - Eugene Usachev,
Tokio делает лучше с точки зрения производительности - это сон
В этом нет ничего удивительного. Вызов sleep в tokio не влечет за собой системный вызов, а лишь говорит планировщику о том, что нужно "не трогать таску" определенное кол-во времени.
Если рассмотреть стандартную библиотеку, то она работает далеко не всегда синхронно. Иногда она "паркует" потоки и "будит" их только в момент готовности.
Это где такое в std встречается, например? При синхронном чтение/записи поток блокируется. Негде его там парковать. Да и для анпаркинга треда в любом случае нужен отдельный тред, который сделает это в случае удовлетворения какого-либо условия.
На моих тестах (как и на тех, что я находил в сети)
Приведите эти тесты, мы же не знаем, что у вас там. Может вы там argon2-хэши считаете или еще какие cpu-bound операции выполняете из-за которых системные потоки себя лучше показывают.
Если есть ещё какой-нибудь тест, где Tokio показывает себя лучше, опишите его.
Человек выше уже привел пример - попробуйте обработать одновременно 10к подключений с токио и без него. Спойлер: во втором случае если и удасться их заспавнить, то cpu будет занят лишь одним - переключением контекста с треда на тред.
- Eugene Usachev, Дело далеко не в производительности. Как уже отметили выше, функционала Токио нет в std. Токио позволяет писать асинхронный код и его выполнять (сам асинхронный код это просто обёртка). Для веб сервисов за частую нужен как раз таки асинхронный подход. Для вычислительных нагрузок асинхронный код может и не нужен, но иногда может быть полезен.
В целом Токио даёт инструмент для concurrency и parallelism. Когда std даёт основу только для parallelism.
- D3lphi,
Спойлер: во втором случае если и удасться их заспавнить, то cpu будет занят лишь одним - переключением контекста с треда на тред.
Я провёл тест на 20 тысячах соединений. Я подключал 20 тысяч соединений к серверу и бесконечно ждал чтения из них. Я согласен, с тем, что Tokio подходит для этих задач лучше, так как он съел в 20 раз меньше памяти. Но я не согласен с нагрузкой на cpu. В обоих случаях она нулевая после старта.
Если делать вывод, то Tokio является лучшим решением для обработки миллионов соединений, так как потребляет меньше памяти. Однако производительность Tokio значительно уступает std.
- Eugene Usachev,
Но я не согласен с нагрузкой на cpu. В обоих случаях она нулевая после старта.
А откуда там нагрузке на cpu взяться? Потоки блокируются и ждут ответа от сетевухи.
Борьба как раз за память и лимит по потокам идёт. - Василий Банников, выше D3lphi написал, что процессор будет занят переключением тредов. Не подтвердилось.
- Eugene Usachev, не выдумывайте. Это вы почему то решили провести нереальный искусственный синтетический тест без реального сетевого взаимодействия, где бесконечно ждали чтения:
Я подключал 20 тысяч соединений к серверу и бесконечно ждал чтения из них.
Я про то, что в тестах нужно заблокировать навсегда все потоки в ожидание результата не писал ни слова.
-
Я провёл тест на 20 тысячах соединений.
Eugene Usachev, 20к тредов как минимум требуют каждый свой стэк, в Rust по умолчанию это 2МБ (можно конечно подтюнить и ужать до 1 страницы в 4КБ, но так не долго stackoverflow словить на пустом месте, хотя я сомневаюсь что Вы тюнили) - 40 гигов на пустом месте сожрали.
бесконечно ждал чтения из них
пока потоки заблокированы на чтении (как и на любом другом блокирующем сисколе), они не будут планироваться, но как только данные пойдут - switch context сожрёт весь перфоманс. Создавать потоков больше чем есть ядер вообще крайне неэффективная идея.
А ещё у каждого потока в системе есть id, которые вполне себе конечные. Если закончится - то в этой системе больше никто не сможет запустить ещё один поток, пока он не освободится и как следствие процессы тоже нельзя будет запустить. Вы даже подключится к такой системе по ssh не сможете, что бы прибить свой сервер.
Ну и 20к одновременных коннектов - это далеко не хайлоад даже.
Ответы:
Rust currently provides only the bare essentials for writing async code. Importantly, executors, tasks, reactors, combinators, and low-level I/O futures and traits are not yet provided in the standard library. In the meantime, community-provided async ecosystems fill in these gaps.
There is no asynchronous runtime in the standard library
Из документации.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
В Rust используют библиотеку Tokio для работы с асинхронным программированием. Tokio предоставляет удобные инструменты для создания эффективных и надежных асинхронных приложений. Он основан на принципах Reactor и Proactor, что позволяет эффективно управлять событиями в асинхронной среде.
Основные преимущества использования Tokio в Rust:
1. Высокая производительность: Tokio предлагает высокую производительность благодаря эффективной обработке событий и мультиплексированию ввода-вывода.
2. Простота использования: Tokio предоставляет удобный API для работы с асинхронными операциями, что упрощает разработку и поддержку кода.
3. Надежность: Tokio обеспечивает надежное выполнение асинхронных задач и обработку ошибок, что повышает стабильность и отказоустойчивость приложения.
4. Масштабируемость: Tokio поддерживает параллельное выполнение операций, что позволяет эффективно использовать ресурсы системы и обеспечивает масштабируемость приложения.
Использование Tokio в Rust позволяет создавать эффективные и надежные асинхронные приложения, что делает эту библиотеку популярным выбором для разработчиков.