# Channels
_Path: en/lua/core/channel_
## Table of Contents
- Channels and Coroutines
## Content
# Channels and Coroutines
Go-style channels for inter-coroutine communication. Create buffered or unbuffered channels, send and receive values, and coordinate between concurrent processes using select statements.
The `channel` global is always available.
## Creating Channels
Unbuffered channels (size 0) require both sender and receiver to be ready before transfer completes. Buffered channels allow sends to complete immediately while space is available:
```lua
-- Unbuffered: synchronizes sender and receiver
local sync_ch = channel.new()
-- Buffered: queue up to 10 messages
local work_queue = channel.new(10)
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `size` | integer | Buffer capacity (default: 0 for unbuffered) |
**Returns:** `channel`
## Sending Values
Send a value to the channel. Blocks until a receiver is ready (unbuffered) or buffer space is available (buffered):
```lua
-- Send work to a worker pool
local jobs = channel.new(100)
for i, task in ipairs(tasks) do
jobs:send(task) -- Blocks if buffer full
end
jobs:close() -- Signal no more work
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `value` | any | Value to send |
**Returns:** `boolean`
Raises error if channel is closed.
## Receiving Values
Receive a value from the channel. Blocks until a value is available or the channel is closed:
```lua
-- Worker consuming from job queue
while true do
local job, ok = work:receive()
if not ok then
break -- Channel closed, no more work
end
process(job)
end
```
**Returns:** `any, boolean`
- `value, true` - Received a value
- `nil, false` - Channel closed and empty
## Closing Channels
Close the channel. Pending senders get an error, pending receivers get `nil, false`. Raises error if already closed:
```lua
local results = channel.new(10)
-- Producer fills results
for _, item in ipairs(data) do
results:send(process(item))
end
results:close() -- Signal completion
```
## Selecting from Multiple Channels
Wait on multiple channel operations simultaneously. Essential for handling multiple event sources, implementing timeouts, and building responsive systems:
```lua
local result = channel.select(cases)
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `cases` | table | Array of select cases |
| `default` | boolean | If true, returns immediately when no case ready |
**Returns:** `table` with fields: `channel`, `value`, `ok`, `default`
### Timeout Pattern
Wait for result with timeout using `time.after()`.
```lua
local time = require("time")
local result_ch = worker:response()
local timeout = time.after("5s")
local r = channel.select {
result_ch:case_receive(),
timeout:case_receive()
}
if r.channel == timeout then
return nil, errors.new("TIMEOUT", "Operation timed out")
end
return r.value
```
### Fan-in Pattern
Merge multiple sources into one handler.
```lua
local events = process.events()
local inbox = process.inbox()
local shutdown = channel.new()
while true do
local r = channel.select {
events:case_receive(),
inbox:case_receive(),
shutdown:case_receive()
}
if r.channel == shutdown then
break
elseif r.channel == events then
handle_event(r.value)
else
handle_message(r.value)
end
end
```
### Non-blocking Check
Check if data is available without blocking.
```lua
local r = channel.select {
ch:case_receive(),
default = true
}
if r.default then
-- Nothing available, do something else
else
process(r.value)
end
```
## Creating Select Cases
Create cases for use with `channel.select`:
```lua
-- Send case - completes when channel can accept value
ch:case_send(value)
-- Receive case - completes when value available
ch:case_receive()
```
## Worker Pool Pattern
```lua
local work = channel.new(100)
local results = channel.new(100)
-- Spawn workers
for i = 1, num_workers do
process.spawn("app.workers:processor", "app:processes", work, results)
end
-- Feed work
for _, item in ipairs(items) do
work:send(item)
end
work:close()
-- Collect results
local processed = {}
while #processed < #items do
local result, ok = results:receive()
if not ok then break end
table.insert(processed, result)
end
```
## Errors
| Condition | Kind | Retryable |
|-----------|------|-----------|
| Send on closed channel | runtime error | no |
| Close of closed channel | runtime error | no |
| Invalid case in select | runtime error | no |
## See Also
- [Process Management](lua/core/process.md) - Process spawning and communication
- [Message Queue](lua/storage/queue.md) - Queue-based messaging
- [Functions](lua/core/funcs.md) - Function invocation
## Navigation
Previous: Time (lua/core/time)
Next: Process (lua/core/process)