mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
sync/channels: provide `try_push(), try_pop() as public methods (#6101)
This commit is contained in:
parent
36eae1c175
commit
c3cdfa1c96
@ -252,7 +252,7 @@ if ch.pop(&m) {
|
|||||||
|
|
||||||
The select call is somewhat tricky. The `channel_select()` function needs three arrays that
|
The select call is somewhat tricky. The `channel_select()` function needs three arrays that
|
||||||
contain the channels, the directions (pop/push) and the object references and
|
contain the channels, the directions (pop/push) and the object references and
|
||||||
a timeout of type `time.Duration` (or `0` to wait unlimited) as parameters. It returns the
|
a timeout of type `time.Duration` (`time.infinite` or `-1` to wait unlimited) as parameters. It returns the
|
||||||
index of the object that was pushed or popped or `-1` for timeout.
|
index of the object that was pushed or popped or `-1` for timeout.
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
39
vlib/sync/bench/results.md
Normal file
39
vlib/sync/bench/results.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Channel Benchmark Results
|
||||||
|
|
||||||
|
This documents lists several benchmark results for different platforms in order to
|
||||||
|
identify performance regressions and improvements.
|
||||||
|
|
||||||
|
The are measured using the command
|
||||||
|
|
||||||
|
```
|
||||||
|
> channel_bench_* <nsend> <nrec> <buflen> <nobj>
|
||||||
|
|
||||||
|
nsend ... number of threads that push objects into the channel
|
||||||
|
nrec .... number of threads that pop objects from the channel
|
||||||
|
buflen .. length of channel buffer queue - `0` means unbuffered channel
|
||||||
|
nobj .... number of objects to pass thru the channel
|
||||||
|
```
|
||||||
|
|
||||||
|
## AMD Ryzen 7 3800X, Ubuntu-20.04 x86_64
|
||||||
|
|
||||||
|
10000000 Objects transfered, results in Objects/µs
|
||||||
|
|
||||||
|
| nsend | nrec | buflen | **V (gcc -O2)** | **V (tcc)** | **Go (glang)** | **Go (gccgo -O2)** |
|
||||||
|
| :---: | :---:| :---: | :---: | :---: | :---: | :---: |
|
||||||
|
| 1 | 1 | 0 | 0.95 | 0.66 | 4.65 | 0.56 |
|
||||||
|
| 1 | 1 | 100 | 3.26 | 2.24 | 18.90 | 6.08 |
|
||||||
|
| 4 | 4 | 0 | 0.25 | 0.24 | 1.84 | 0.84 |
|
||||||
|
| 4 | 4 | 100 | 2.78 | 2.63 | 7.43 | 3.71 |
|
||||||
|
|
||||||
|
## Raspberry Pi 3B+, Void Linux musl 32 bit
|
||||||
|
|
||||||
|
10000000 Objects transfered, results in Objects/µs
|
||||||
|
|
||||||
|
| nsend | nrec | buflen | **V (gcc -O2)** | **Go (glang)** |
|
||||||
|
| :---: | :---:| :---: | :---: | :---: |
|
||||||
|
| 1 | 1 | 0 | 0.37 | 0.21 |
|
||||||
|
| 1 | 1 | 100 | 1.03 | 0.74 |
|
||||||
|
| 4 | 4 | 0 | 0.04 | 0.38 |
|
||||||
|
| 4 | 4 | 100 | 2.78 | 2.63 |
|
||||||
|
| 2 | 2 | 0 | 0.05 | 0.38 |
|
||||||
|
| 2 | 2 | 100 | 1.26 | 0.75 |
|
@ -48,7 +48,7 @@ fn test_select() {
|
|||||||
mut sl := i64(0)
|
mut sl := i64(0)
|
||||||
mut objs := [voidptr(&ri), &sl, &rl, &rb]
|
mut objs := [voidptr(&ri), &sl, &rl, &rb]
|
||||||
for _ in 0 .. 1200 {
|
for _ in 0 .. 1200 {
|
||||||
idx := sync.channel_select(mut channels, directions, mut objs, 0)
|
idx := sync.channel_select(mut channels, directions, mut objs, -1)
|
||||||
match idx {
|
match idx {
|
||||||
0 {
|
0 {
|
||||||
sum += ri
|
sum += ri
|
||||||
|
@ -152,17 +152,26 @@ pub fn (mut ch Channel) close() {
|
|||||||
C.atomic_store_u16(&ch.write_sub_mtx, u16(0))
|
C.atomic_store_u16(&ch.write_sub_mtx, u16(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
pub fn (mut ch Channel) push(src voidptr) {
|
pub fn (mut ch Channel) push(src voidptr) {
|
||||||
if ch.try_push(src, false) == .closed {
|
if ch.try_push_priv(src, false) == .closed {
|
||||||
panic('push on closed channel')
|
panic('push on closed channel')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut ch Channel) try_push(src voidptr, no_block bool) TransactionState {
|
[inline]
|
||||||
|
pub fn (mut ch Channel) try_push(src voidptr) TransactionState {
|
||||||
|
return ch.try_push_priv(src, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut ch Channel) try_push_priv(src voidptr, no_block bool) TransactionState {
|
||||||
if C.atomic_load_u16(&ch.closed) != 0 {
|
if C.atomic_load_u16(&ch.closed) != 0 {
|
||||||
return .closed
|
return .closed
|
||||||
}
|
}
|
||||||
spinloops_, spinloops_sem_ := if no_block { 1, 1 } else { spinloops, spinloops_sem }
|
mut spinloops_sem_, spinloops_ := if no_block { spinloops, spinloops_sem } else { 1, 1 }
|
||||||
|
$if macos {
|
||||||
|
spinloops_sem_ = 1
|
||||||
|
}
|
||||||
mut have_swapped := false
|
mut have_swapped := false
|
||||||
for {
|
for {
|
||||||
mut got_sem := false
|
mut got_sem := false
|
||||||
@ -307,12 +316,21 @@ fn (mut ch Channel) try_push(src voidptr, no_block bool) TransactionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
pub fn (mut ch Channel) pop(dest voidptr) bool {
|
pub fn (mut ch Channel) pop(dest voidptr) bool {
|
||||||
return ch.try_pop(dest, false) == .success
|
return ch.try_pop_priv(dest, false) == .success
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut ch Channel) try_pop(dest voidptr, no_block bool) TransactionState {
|
[inline]
|
||||||
spinloops_, spinloops_sem_ := if no_block { 1, 1 } else { spinloops, spinloops_sem }
|
pub fn (mut ch Channel) try_pop(dest voidptr) TransactionState {
|
||||||
|
return ch.try_pop_priv(dest, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut ch Channel) try_pop_priv(dest voidptr, no_block bool) TransactionState {
|
||||||
|
mut spinloops_sem_, spinloops_ := if no_block { spinloops, spinloops_sem } else { 1, 1 }
|
||||||
|
$if macos {
|
||||||
|
spinloops_sem_ = 1
|
||||||
|
}
|
||||||
mut have_swapped := false
|
mut have_swapped := false
|
||||||
mut write_in_progress := false
|
mut write_in_progress := false
|
||||||
for {
|
for {
|
||||||
@ -465,7 +483,11 @@ fn (mut ch Channel) try_pop(dest voidptr, no_block bool) TransactionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait `timeout` on any of `channels[i]` until one of them can push (`is_push[i] = true`) or pop (`is_push[i] = false`)
|
// Wait `timeout` on any of `channels[i]` until one of them can push (`is_push[i] = true`) or pop (`is_push[i] = false`)
|
||||||
// object referenced by `objrefs[i]`. `timeout = 0` means wait unlimited time
|
// object referenced by `objrefs[i]`. `timeout < 0` means wait unlimited time. `timeout == 0` means return immediately
|
||||||
|
// if no transaction can be performed without waiting.
|
||||||
|
// return value: the index of the channel on which a transaction has taken place
|
||||||
|
// -1 if waiting for a transaction has exceeded timeout
|
||||||
|
// -2 if all channels are closed
|
||||||
|
|
||||||
pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []voidptr, timeout time.Duration) int {
|
pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []voidptr, timeout time.Duration) int {
|
||||||
assert channels.len == dir.len
|
assert channels.len == dir.len
|
||||||
@ -499,7 +521,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||||||
C.atomic_store_u16(&ch.read_sub_mtx, u16(0))
|
C.atomic_store_u16(&ch.read_sub_mtx, u16(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stopwatch := if timeout == 0 { time.StopWatch{} } else { time.new_stopwatch({}) }
|
stopwatch := if timeout <= 0 { time.StopWatch{} } else { time.new_stopwatch({}) }
|
||||||
mut event_idx := -1 // negative index means `timed out`
|
mut event_idx := -1 // negative index means `timed out`
|
||||||
for {
|
for {
|
||||||
rnd := rand.u32_in_range(0, u32(channels.len))
|
rnd := rand.u32_in_range(0, u32(channels.len))
|
||||||
@ -510,7 +532,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||||||
i -= channels.len
|
i -= channels.len
|
||||||
}
|
}
|
||||||
if dir[i] == .push {
|
if dir[i] == .push {
|
||||||
stat := channels[i].try_push(objrefs[i], true)
|
stat := channels[i].try_push_priv(objrefs[i], true)
|
||||||
if stat == .success {
|
if stat == .success {
|
||||||
event_idx = i
|
event_idx = i
|
||||||
goto restore
|
goto restore
|
||||||
@ -518,7 +540,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||||||
num_closed++
|
num_closed++
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stat := channels[i].try_pop(objrefs[i], true)
|
stat := channels[i].try_pop_priv(objrefs[i], true)
|
||||||
if stat == .success {
|
if stat == .success {
|
||||||
event_idx = i
|
event_idx = i
|
||||||
goto restore
|
goto restore
|
||||||
@ -531,7 +553,9 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||||||
event_idx = -2
|
event_idx = -2
|
||||||
goto restore
|
goto restore
|
||||||
}
|
}
|
||||||
if timeout > 0 {
|
if timeout == 0 {
|
||||||
|
goto restore
|
||||||
|
} else if timeout > 0 {
|
||||||
remaining := timeout - stopwatch.elapsed()
|
remaining := timeout - stopwatch.elapsed()
|
||||||
if !sem.timed_wait(remaining) {
|
if !sem.timed_wait(remaining) {
|
||||||
goto restore
|
goto restore
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import sync
|
import sync
|
||||||
|
import time
|
||||||
|
|
||||||
fn do_rec_i64(mut ch sync.Channel) {
|
fn do_rec_i64(mut ch sync.Channel) {
|
||||||
mut sum := i64(0)
|
mut sum := i64(0)
|
||||||
@ -55,7 +56,7 @@ fn test_select() {
|
|||||||
mut sl := i64(0)
|
mut sl := i64(0)
|
||||||
mut objs := [voidptr(&ri), &sl, &rl, &rb]
|
mut objs := [voidptr(&ri), &sl, &rl, &rb]
|
||||||
for j in 0 .. 1101 {
|
for j in 0 .. 1101 {
|
||||||
idx := sync.channel_select(mut channels, directions, mut objs, 0)
|
idx := sync.channel_select(mut channels, directions, mut objs, time.infinite)
|
||||||
match idx {
|
match idx {
|
||||||
0 {
|
0 {
|
||||||
sum += ri
|
sum += ri
|
||||||
|
@ -363,9 +363,10 @@ pub const(
|
|||||||
nanosecond = Duration(1)
|
nanosecond = Duration(1)
|
||||||
microsecond = Duration(1000) * nanosecond
|
microsecond = Duration(1000) * nanosecond
|
||||||
millisecond = Duration(1000) * microsecond
|
millisecond = Duration(1000) * microsecond
|
||||||
second = Duration(1000) * millisecond
|
second = Duration(1000) * millisecond
|
||||||
minute = Duration(60) * second
|
minute = Duration(60) * second
|
||||||
hour = Duration(60) * minute
|
hour = Duration(60) * minute
|
||||||
|
infinite = Duration(-1)
|
||||||
)
|
)
|
||||||
|
|
||||||
// nanoseconds returns the duration as an integer number of nanoseconds.
|
// nanoseconds returns the duration as an integer number of nanoseconds.
|
||||||
|
Loading…
Reference in New Issue
Block a user