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
Channels are the preferred way to communicate between threads. V's channels work basically like Channels are the preferred way to communicate between threads. They allow threads to exchange data
those in Go. You can push objects into a channel on one end and pop objects from the other end. safely without requiring explicit locking. V's channels are similar to those in Go, enabling you
Channels can be buffered or unbuffered and it is possible to `select` from multiple channels. 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 #### Syntax and Usage
Channels have the type `chan objtype`. An optional buffer length can be specified as the `cap` field Channels are declared with the type `chan objtype`.
in the declaration: You can optionally specify a buffer length using the `cap` field:
```v ```v
ch := chan int{} // unbuffered - "synchronous" 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 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: variables:
```v ```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() { fn main() {
ch := chan int{} ch := chan int{cap: 5}
spawn f(ch) 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 #### Buffered Channels
pop objects from the other end:
Buffered channels allow you to push multiple items without blocking,
as long as the buffer is not full:
```v ```v
// make buffered channels so pushing does not block (if there is room in the buffer) ch := chan string{cap: 2}
ch := chan int{cap: 1} ch <- 'hello'
ch2 := chan f64{cap: 1} ch <- 'world'
n := 5 // ch <- '!' // This would block because the buffer is full
// push
ch <- n println(<-ch) // "hello"
ch2 <- 7.3 println(<-ch) // "world"
mut y := f64(0.0)
m := <-ch // pop creating new variable
y = <-ch2 // pop into existing variable
``` ```
#### Closing Channels
A channel can be closed to indicate that no further objects can be pushed. Any attempt 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 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 `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: 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 ```v
struct Abc { struct Abc {
x int 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 The underlying `struct` contains a hidden *mutex* that allows locking concurrent access
using `rlock` for read-only and `lock` for read/write 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 ```v
struct St { struct Counter {
mut: mut:
x int // data to be shared value int
} }
fn (shared b St) g() { fn (shared counter Counter) increment() {
lock b { lock counter {
// read/modify/write b.x counter.value += 1
println('Incremented to: ${counter.value}')
} }
} }
fn main() { fn main() {
shared a := St{ shared counter := Counter{}
x: 10
} spawn counter.increment()
spawn a.g() spawn counter.increment()
// ...
rlock a { rlock counter {
// read a.x 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 ## JSON