Channels in Desi¶
Channels provide thread-safe message passing between concurrent tasks. They're the primary way to communicate data between spawned tasks.
Quick Start¶
import sync
def main() -> int:
# Create a bounded channel with capacity 10
let ch = sync.Channel(10)
# Get sender and receiver handles
let tx = ch.sender()
let rx = ch.receiver()
# Send a value
tx.send(42)
# Receive the value
match rx.recv():
Option.Some(v): print(v) # Prints: 42
Option.Nothing: print("Channel closed")
return 0
Creating Channels¶
Channels are bounded - they have a fixed capacity:
import sync
# Create channel with capacity 10
let ch = sync.Channel(10)
# Or use from-import
from sync import Channel
let ch = Channel(10)
Senders and Receivers¶
Channels use separate sender and receiver handles:
let tx = ch.sender() # Get a sender
let rx = ch.receiver() # Get a receiver
# Send values
tx.send(1)
tx.send(2)
tx.send(3)
# Close when done sending
ch.close()
Sending Values¶
Blocking Send¶
send() blocks if the channel is full:
Non-blocking Send¶
try_send() returns immediately:
Receiving Values¶
Blocking Receive¶
recv() blocks until a value is available:
Non-blocking Receive¶
try_recv() returns immediately:
Closing Channels¶
Close a channel to signal no more values will be sent:
After closing:
- send() and try_send() return false
- recv() returns remaining values, then Nothing
Example: Producer-Consumer¶
import sync
def main() -> int:
let ch = sync.Channel(5)
let tx = ch.sender()
let rx = ch.receiver()
# Send multiple values
tx.send(1)
tx.send(2)
tx.send(3)
# Close channel
ch.close()
print("Producer-Consumer complete!")
return 0
Best Practices¶
- Always close channels when done sending to prevent receiver blocking
- Use bounded channels to prevent unbounded memory growth
- Use
try_send/try_recvwhen you don't want to block - Handle
Nothingcase when receiving - channel may be closed
Import Styles¶
Both import styles work:
# Module import
import sync
let ch = sync.Channel(10)
# Direct import
from sync import Channel
let ch = Channel(10)