Задачи
В Rust есть система задач, которая представляет собой форму лёгких потоков.
Задача имеет один верхнеуровневый фьючерс, который исполнитель опрашивает, чтобы продвигать работу. Этот фьючерс может иметь один или несколько вложенных фьючерсов, которые его метод poll опрашивает, что приблизительно соответствует стеку вызовов. Конкурентность внутри задачи возможна за счёт опроса нескольких дочерних фьючерсов, например гонки таймера и операции ввода-вывода.
// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:0").await?;
println!("listening on port {}", listener.local_addr()?.port());
loop {
let (mut socket, addr) = listener.accept().await?;
println!("connection from {addr:?}");
tokio::spawn(async move {
socket.write_all(b"Who are you?\n").await.expect("socket error");
let mut buf = vec![0; 1024];
let name_size = socket.read(&mut buf).await.expect("socket error");
let name = std::str::from_utf8(&buf[..name_size]).unwrap().trim();
let reply = format!("Thanks for dialing in, {name}!\n");
socket.write_all(reply.as_bytes()).await.expect("socket error");
});
}
}
Скопируйте этот пример в подготовленный src/main.rs и запустите его оттуда.
Попробуйте подключиться к нему с помощью инструмента для TCP-соединений, например nc или telnet.
-
Попросите студентов представить, каким будет состояние примера сервера с несколькими подключёнными клиентами. Какие задачи существуют? Каковы их фьючерсы?
-
Это первый раз, когда мы видим блок
async. Он похож на замыкание, но не принимает аргументов. Его возвращаемое значение — фьючерс, как и уasync fn. -
Перепишите блок async в функцию и улучшите обработку ошибок с помощью
?.