doc: improve Shared and Channels's topics, add more examples (#24155)

This commit is contained in:
Hitalo Souza 2025-04-09 05:49:06 +01:00 committed by GitHub
parent aba4a5ae4a
commit 2f7cf4df41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -4495,18 +4495,20 @@ fn main() {
### Channels
Channels are the preferred way to communicate between threads. V's channels work basically like
those in Go. You can push objects into a channel on one end and pop objects from the other end.
Channels can be buffered or unbuffered and it is possible to `select` from multiple channels.
Channels are the preferred way to communicate between threads. They allow threads to exchange data
safely without requiring explicit locking. V's channels are similar to those in Go, enabling you
to push objects into a channel on one end and pop objects from the other.
Channels can be buffered or unbuffered, and you can use the `select` statement to monitor multiple
channels simultaneously.
#### Syntax and Usage
Channels have the type `chan objtype`. An optional buffer length can be specified as the `cap` field
in the declaration:
Channels are declared with the type `chan objtype`.
You can optionally specify a buffer length using the `cap` field:
```v
ch := chan int{} // unbuffered - "synchronous"
ch2 := chan f64{cap: 100} // buffer length 100
ch2 := chan f64{cap: 100} // buffered with a capacity of 100
```
Channels do not have to be declared as `mut`. The buffer length is not part of the type but
@ -4514,33 +4516,54 @@ a field of the individual channel object. Channels can be passed to threads like
variables:
```v
fn f(ch chan int) {
// ...
import time
fn worker(ch chan int) {
for i in 0 .. 5 {
ch <- i // push values into the channel
}
}
fn clock(ch chan int) {
for i in 0 .. 5 {
time.sleep(1 * time.second)
println('Clock tick')
ch <- (i + 1000) // push a value into the channel
}
ch.close() // close the channel when done
}
fn main() {
ch := chan int{}
spawn f(ch)
// ...
ch := chan int{cap: 5}
spawn worker(ch)
spawn clock(ch)
for {
value := <-ch or { // receive/pop values from the channel
println('Channel closed')
break
}
println('Received: ${value}')
}
}
```
Objects can be pushed to channels using the arrow operator. The same operator can be used to
pop objects from the other end:
#### Buffered Channels
Buffered channels allow you to push multiple items without blocking,
as long as the buffer is not full:
```v
// make buffered channels so pushing does not block (if there is room in the buffer)
ch := chan int{cap: 1}
ch2 := chan f64{cap: 1}
n := 5
// push
ch <- n
ch2 <- 7.3
mut y := f64(0.0)
m := <-ch // pop creating new variable
y = <-ch2 // pop into existing variable
ch := chan string{cap: 2}
ch <- 'hello'
ch <- 'world'
// ch <- '!' // This would block because the buffer is full
println(<-ch) // "hello"
println(<-ch) // "world"
```
#### Closing Channels
A channel can be closed to indicate that no further objects can be pushed. Any attempt
to do so will then result in a runtime panic (with the exception of `select` and
`try_push()` - see below). Attempts to pop will return immediately if the
@ -4635,6 +4658,14 @@ if select {
For special purposes there are some builtin fields and methods:
```v
ch := chan int{cap: 2}
println(ch.try_push(42)) // `.success` if pushed, `.not_ready` if full, `.closed` if closed
println(ch.len) // Number of items in the buffer
println(ch.cap) // Buffer capacity
println(ch.closed) // Whether the channel is closed
```
```v
struct Abc {
x int
@ -4670,31 +4701,44 @@ Such variables should be created as `shared` and passed to the thread as such, t
The underlying `struct` contains a hidden *mutex* that allows locking concurrent access
using `rlock` for read-only and `lock` for read/write access.
Note: Shared variables must be structs, arrays or maps.
#### Example of Shared Objects
```v
struct St {
struct Counter {
mut:
x int // data to be shared
value int
}
fn (shared b St) g() {
lock b {
// read/modify/write b.x
fn (shared counter Counter) increment() {
lock counter {
counter.value += 1
println('Incremented to: ${counter.value}')
}
}
fn main() {
shared a := St{
x: 10
}
spawn a.g()
// ...
rlock a {
// read a.x
shared counter := Counter{}
spawn counter.increment()
spawn counter.increment()
rlock counter {
println('Final value: ${counter.value}')
}
}
```
Shared variables must be structs, arrays or maps.
### Difference Between Channels and Shared Objects
**Purpose**:
- Channels: Used for message passing between threads, ensuring safe communication.
- Shared objects: Used for direct data sharing and modification between threads.
**Synchronization**:
- Channels: Implicit (via channel operations)
- Shared objects: Explicit (via `rlock`/`lock` blocks)
## JSON