### **Практическое задание: задачи с таймаутом** Создайте метод TaskPool::create, которая будет отправлять задачу в канал, но если не получается отправить задачу в канал в течение 100 миллисекунд, возвращается None ```rust use std::time::{Duration, Instant}; use tokio::{ sync::mpsc::{Receiver, Sender, channel, error::SendError}, time::timeout, }; struct TaskPool { tasks: Receiver, sender: Sender, } impl TaskPool { fn new(queue_size: usize) -> Self { let (sender, tasks) = channel::(queue_size); Self { tasks, sender } } async fn create(&self, task: T) -> Option>> { // Напишите свое решение здесь } async fn pull_task(&mut self) -> Option { self.tasks.recv().await } } #[tokio::main] async fn main() { let mut tasks = TaskPool::new(2); assert_eq!(tasks.create(()).await, Some(Ok(()))); assert_eq!(tasks.create(()).await, Some(Ok(()))); let start = Instant::now(); assert_eq!(tasks.create(()).await, None); let end = start.elapsed(); assert!(end > Duration::from_millis(90)); assert!(end < Duration::from_millis(110)); assert_eq!(tasks.pull_task().await, Some(())); assert_eq!(tasks.create(()).await, Some(Ok(()))); } ``` ### Подсказки используйте tokio::time::timeout для таймаута tokio::time::timeout принимает фьючерс для которого нужен таймаут используйте .send() для отправки значение обратите внимание, что .send() возвращает фьючерс Проверьте свой код по чек-листу: используется tokio::time::timeout используются асинхронные каналы все тесты проходят ### **Решение** ```rust async fn create(&self, task: T) -> Option>> { let sender = self.sender.send(task); timeout(Duration::from_millis(100), sender).await.ok() } ``` Вы знаете про существование таких синхронизационных примитивов в стандартной библиотеке, как Mutex, RwLock, каналы. И в тоже происходит ожидание. Но они блокируют поток, поэтому в tokio есть альтернативы с идентичным интерфейсом, но асинхронным: У асинхронных мьютекса и RwLock есть преимущество: если фьючерс ожидает лока асинхронного мьютекса, токио будет обратно переключаться на другие фьючерсы. В то время, как синхронные версии будут держать поток и не давать другим фьючерсам исполняться. Для синхронных версий это создает проблему: если MutexGuard пересек границу .await, где, к примеру, ожидается ответ в течение 30 секунд, то другой фьючерс, ожидающий лока мьютекса, будет держать целый поток токио в течение всего этого времени, что приведет к потере производительности. А если рантайм токио будет однопоточным, то программа зависнет навсегда. после вызова await залочен, что приводит к ожиданию анлока от других