3.3Kпросмотров
26 марта 2025 г.
Score: 3.6K
Аналог блокирующей очереди для корутин ⛓ В одном из предыдущих постов мы обсуждали удобство использования блокирующий очереди (интерфейс java.util.concurrent.BlockingQueue), для коммуникации между потоками. Одна группа потоков помещают данные в хвост очереди, другая группа получает данные из ее головы. Почему бы нам не использовать такую же очередь для общения корутин друг с другом? 🏈 Дело в том, что операции BlockingQueue могут заблокировать поток исполнения: - Получение элемента блокируется, если очередь пуста - Вставка в очередь может блокироваться, если максимальный размер очереди уже достигнут 🧨 Но использовать внутри корутин операции, блокирующие поток, антипаттерн. Поэтому, например, существует отдельный набор мьютексов, которые не блокируют поток, а реализуют взаимное исключение именно для корутин. 🥁 Есть ли неблокирующий аналог для BlockingQueue в мире корутин? Да, интерфейс kotlinx.coroutines.channels.Channel и его реализации концептуально являются воплощениями блокирующей очереди. "Канал" предоставляет методы send и receive, которые тоже обладают блокирующей семантикой, но блокируют они корутину, а не поток, на котором она исполняется. ✍️ Как и очередь, ченнел может иметь ограниченный размер буфера элементов. Вы можете определить его, передав в конструктор. Но есть специальные, зарезервированные значения длины буфера, в зависимости от которых вам будет предоставлена наиболее оптимальная реализация канала. Например, в качестве размера вы можете передать следующие константы: 1. Channel.RENDEZVOUS: в этом случае вам будет создан канал не имеющий никакого буфера. Каждый вызов метода send будет блокировать корутину, пока на встречу (на рандеву) с ним не придет соответствующий метод receive. 2. Channel.UNLIMITED: тут все понятно, буфер будет “бесконечным”, что фактически можно читать, как “сколько памяти хватит”. Метод send в этой реализации не заблокирует корутину никогда. 3. Channel.CONFLATED: довольно интересная реализация канала. Поддерживает буфер размером в один элемент. Каждый последний вызов метода send подменяет то, что было записано ранее. Метод receive соответственно всегда прочитает последнее записанное значение. Как и в прошлом пункте метод send никогда не блокируется. Создание ченнела с размером буфера равным десяти, запись и чтение из него: val channel = Channel<Element>(capacity) // Producer code
channel.send(elementToSend) // Consumer code
val elementReceived = channel.receive() Ставьте 🔥, если было полезно и отвечайте на опрос ниже ⬇️ #kotlin #coroutines