Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Модуль 4.3 — Асинхронная многозадачность

Слайды

Упражнение 4.3.1: От синхронного кода к асинхронному

Синхронный и асинхронный код на Rust выглядят не так уж по-разному. В этом упражнении мы превратим синхронный TCP-эхо-сервер на Rust в асинхронный.

Откройте exercises/4-multitasking/3-asynchronous-multitasking/1-sync-to-async в редакторе. Следуя шагам в main.rs, сначала проверьте, что программа работает, затем преобразуйте её в async и снова проверьте, что она работает.

Упражнение 4.3.2: Приёмник данных измерений

В этом сценарии есть набор IoT-датчиков, которые измеряют качество воздуха в разных комнатах. Они отправляют данные через TCP-сокет на сервер. Сервер агрегирует данные по комнатам и записывает их в CSV-файл. Сейчас эта функциональность реализована синхронно. Ваша задача — сделать серверный код async.

Откройте exercises/4-multitasking/3-asynchronous-multitasking/2-measurement-data-sink в редакторе.

В двух разных терминалах запустите:

cargo run --bin server

и

cargo run --bin sensor-nodes

Вы должны увидеть регулярные лог-сообщения о полученных измерениях. Каждые 60 секунд в database.csv будут добавляться новые строки.

Упражнение 4.3.2A: async-изация

Затем разберитесь с комментариями TODO: в src/bin/server.rs. Проверьте, что приложение по-прежнему работает, как и раньше.

Упражнение 4.3.2B: Изменение требований

Запустите клиентов с интервалом 10 секунд:

cargo run --bin sensor-nodes -- -i 10s

Разберитесь с возникающими ошибками и устраните их.

Упражнение 4.3.3: Асинхронные каналы

Каналы — очень удобный способ обмениваться сообщениями между потоками и async-задачами. Они позволяют разбить приложение на множество слабо связанных задач. Вы увидите, как это пригодится в упражнении E.2. В этом упражнении вы реализуете два варианта: oneshot-канал и канал «много отправителей — один получатель» (multi-producer-single-consumer, MPSC). Если хочется испытать себя, можно написать и broadcast-канал.

4.3.3.A Канал MPSC ⭐⭐

Канал MPSC (multi-producer-single-consumer) позволяет нескольким Sender отправлять много сообщений одному Receiver.

Откройте exercises/4-multitasking/3-asynchronous-multitasking/3-async-channels в редакторе. Там вы найдёте заготовку кода. Для части A работайте в src/mpsc.rs. Исправьте todo! в этом файле, чтобы тест прошёл. Для проверки выполните:

cargo test -- mpsc

Если тесты зависают, скорее всего, ваша реализация неправильно использует Waker или возвращает Poll::Pending там, где не должна.

4.3.3.B Oneshot-канал ⭐⭐⭐

Oneshot — канал, который позволяет одному Sender отправить ровно одно сообщение одному Receiver.

Для части B работайте в src/broadcast.rs. На этот раз больше придётся сделать самостоятельно. Ожидаемое поведение:

  • Receiver реализует Future. Он возвращает Poll::Ready(Ok(T)), если inner.data равно Some(T); Poll::Pending, если inner.data равно None; и Poll::Ready(Err(Error::SenderDropped)), если Sender был уничтожен.
  • Receiver::poll заменяет inner.waker на тот, что пришёл в Context.
  • Sender потребляет self при отправке, поэтому его можно использовать не более одного раза. Отправка устанавливает inner.data в Some(T). Если Receiver был уничтожен до отправки, возвращается Err(Error::ReceiverDropped(T)).
  • Sender::send будит inner.waker после того, как записал данные в inner.data.
  • Когда Sender уничтожается, он помечает себя уничтоженным в inner.
  • Когда Receiver уничтожается, он помечает себя уничтоженным в inner.
  • После успешной отправки потреблённый Sender не помечается как уничтоженный. Вместо этого используется std::mem::forget, чтобы не запускать деструктор.

Для проверки выполните:

cargo test -- broadcast

4.3.3.C Broadcast-канал (бонус) ⭐⭐⭐⭐

Broadcast-канал поддерживает несколько отправителей и несколько получателей. Каждое сообщение, отправленное любым из отправителей, получает каждый получатель. Поэтому реализация должна хранить сообщения, пока их не получит каждый ещё не уничтоженный получатель. Из этого также следует, что при рассылке сообщение нужно клонировать.

В этом бонусном упражнении заготовки нет. Вдохновляйтесь модулями mpsc и oneshot и реализуйте модуль broadcast самостоятельно.