Каналы и конкурентность
Каналы и конкурентность
Заголовок раздела «Каналы и конкурентность»Каналы в стиле Go для конкурентного программирования внутри процессов.
Создание каналов
Заголовок раздела «Создание каналов»Каналы — это коммуникационные трубы для корутин. Создаются с помощью channel.new(capacity):
local ch = channel.new(1) -- buffered channel, capacity 1Буферизированные каналы
Заголовок раздела «Буферизированные каналы»Буферизированные каналы позволяют отправлять данные без блокировки, пока буфер не заполнен:
local ch = channel.new(3) -- buffer holds 3 items
-- Send without blockingch:send(1)ch:send(2)ch:send(3)
-- Receive in FIFO orderlocal v1, ok1 = ch:receive() -- 1, truelocal v2, ok2 = ch:receive() -- 2, truelocal v3, ok3 = ch:receive() -- 3, trueНебуферизированные каналы
Заголовок раздела «Небуферизированные каналы»Небуферизированные каналы (ёмкость 0) синхронизируют отправителя и получателя:
local ch = channel.new(0) -- unbufferedlocal done = channel.new(1)
coroutine.spawn(function() ch:send("from spawn") -- blocks until receiver ready done:send(true)end)
local val = ch:receive() -- receives "from spawn"local completed = done:receive()Выбор из каналов
Заголовок раздела «Выбор из каналов»channel.select ожидает несколько каналов и возвращает первую готовую операцию:
local ch1 = channel.new(1)local ch2 = channel.new(1)
ch1:send("ch1_value")
local result = channel.select{ ch1:case_receive(), ch2:case_receive()}
-- result is a table with: channel, value, okresult.channel == ch1 -- trueresult.value -- "ch1_value"result.ok -- trueSelect с отправкой
Заголовок раздела «Select с отправкой»Используйте case_send для неблокирующей отправки:
local ch = channel.new(1)
local result = channel.select{ ch:case_send("sent")}
result.ok -- true (send succeeded)
local v = ch:receive() -- "sent"Паттерн “производитель-потребитель”
Заголовок раздела «Паттерн “производитель-потребитель”»Один производитель, один потребитель:
local ch = channel.new(5)local done = channel.new(1)local consumed = 0
-- Consumercoroutine.spawn(function() while true do local v, ok = ch:receive() if not ok then break end consumed = consumed + 1 end done:send(consumed)end)
-- Producerfor i = 1, 10 do ch:send(i)endch:close()
local total = done:receive() -- 10Паттерн “пинг-понг”
Заголовок раздела «Паттерн “пинг-понг”»Синхронизация двух корутин:
local ping = channel.new(0)local pong = channel.new(0)local rounds_done = channel.new(1)
coroutine.spawn(function() for i = 1, 5 do ping:receive() pong:send("pong") end rounds_done:send(true)end)
for i = 1, 5 do ping:send("ping") pong:receive()end
local completed = rounds_done:receive()Паттерн Fan-Out
Заголовок раздела «Паттерн Fan-Out»Один производитель, несколько потребителей:
local work = channel.new(10)local results = channel.new(10)
-- Spawn 3 workersfor w = 1, 3 do coroutine.spawn(function() while true do local job, ok = work:receive() if not ok then break end results:send(job * 2) end end)end
-- Send workfor i = 1, 6 do work:send(i)endwork:close()
-- Collect resultslocal sum = 0for i = 1, 6 do local r = results:receive() sum = sum + rend-- sum = (1+2+3+4+5+6)*2 = 42Паттерн Fan-In
Заголовок раздела «Паттерн Fan-In»Несколько производителей, один потребитель:
local output = channel.new(10)local producer_count = 4local items_per_producer = 5
-- Spawn producersfor p = 1, producer_count do coroutine.spawn(function() for i = 1, items_per_producer do output:send({producer = p, item = i}) end end)end
-- Collect all messageslocal received = {}for i = 1, producer_count * items_per_producer do local msg = output:receive() table.insert(received, msg)end
-- Verify all producers sent their itemslocal counts = {}for _, msg in ipairs(received) do counts[msg.producer] = (counts[msg.producer] or 0) + 1endЗакрытие каналов
Заголовок раздела «Закрытие каналов»Закрывайте каналы для сигнализации завершения. Получатели получают ok = false, когда канал закрыт и пуст:
local ch = channel.new(5)local done = channel.new(1)
coroutine.spawn(function() local count = 0 while true do local v, ok = ch:receive() if not ok then break end -- channel closed count = count + 1 end done:send(count)end)
for i = 1, 10 do ch:send(i)endch:close() -- signal no more values
local total = done:receive()Методы каналов
Заголовок раздела «Методы каналов»Доступные операции:
channel.new(capacity)- Создать канал с заданным размером буфераch:send(value)- Отправить значение (блокируется, если буфер полон)ch:receive()- Получить значение, возвращаетvalue, okch:close()- Закрыть каналch:case_send(value)- Создать случай отправки для selectch:case_receive()- Создать случай получения для selectchannel.select{cases...}- Ожидать несколько операций
Следующие шаги
Заголовок раздела «Следующие шаги»- Справочник модуля каналов - Полная документация API
- Процессы - Межпроцессное взаимодействие