mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-07 04:23:41 +00:00
Improved blocking (#513)
core: major improvements to blocking, including support for buffered channels.
This commit is contained in:
Vendored
+104
-8
@@ -1,65 +1,110 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// waitGroup is a small type reimplementing some of the behavior of sync.WaitGroup
|
||||
type waitGroup uint
|
||||
|
||||
func (wg *waitGroup) wait() {
|
||||
n := 0
|
||||
for *wg != 0 {
|
||||
// pause and wait to be rescheduled
|
||||
runtime.Gosched()
|
||||
|
||||
if n > 100 {
|
||||
// if something is using the sleep queue, this may be necessary
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *waitGroup) add(n uint) {
|
||||
*wg += waitGroup(n)
|
||||
}
|
||||
|
||||
func (wg *waitGroup) done() {
|
||||
if *wg == 0 {
|
||||
panic("wait group underflow")
|
||||
}
|
||||
*wg--
|
||||
}
|
||||
|
||||
var wg waitGroup
|
||||
|
||||
func main() {
|
||||
ch := make(chan int)
|
||||
println("len, cap of channel:", len(ch), cap(ch), ch == nil)
|
||||
|
||||
wg.add(1)
|
||||
go sender(ch)
|
||||
|
||||
n, ok := <-ch
|
||||
println("recv from open channel:", n, ok)
|
||||
|
||||
for n := range ch {
|
||||
if n == 6 {
|
||||
time.Sleep(time.Microsecond)
|
||||
}
|
||||
println("received num:", n)
|
||||
}
|
||||
|
||||
wg.wait()
|
||||
n, ok = <-ch
|
||||
println("recv from closed channel:", n, ok)
|
||||
|
||||
// Test bigger values
|
||||
ch2 := make(chan complex128)
|
||||
wg.add(1)
|
||||
go sendComplex(ch2)
|
||||
println("complex128:", <-ch2)
|
||||
wg.wait()
|
||||
|
||||
// Test multi-sender.
|
||||
ch = make(chan int)
|
||||
wg.add(3)
|
||||
go fastsender(ch, 10)
|
||||
go fastsender(ch, 23)
|
||||
go fastsender(ch, 40)
|
||||
slowreceiver(ch)
|
||||
wg.wait()
|
||||
|
||||
// Test multi-receiver.
|
||||
ch = make(chan int)
|
||||
wg.add(3)
|
||||
go fastreceiver(ch)
|
||||
go fastreceiver(ch)
|
||||
go fastreceiver(ch)
|
||||
slowsender(ch)
|
||||
wg.wait()
|
||||
|
||||
// Test iterator style channel.
|
||||
ch = make(chan int)
|
||||
wg.add(1)
|
||||
go iterator(ch, 100)
|
||||
sum := 0
|
||||
for i := range ch {
|
||||
sum += i
|
||||
}
|
||||
wg.wait()
|
||||
println("sum(100):", sum)
|
||||
|
||||
// Test simple selects.
|
||||
go selectDeadlock()
|
||||
go selectDeadlock() // cannot use waitGroup here - never terminates
|
||||
wg.add(1)
|
||||
go selectNoOp()
|
||||
wg.wait()
|
||||
|
||||
// Test select with a single send operation (transformed into chan send).
|
||||
ch = make(chan int)
|
||||
wg.add(1)
|
||||
go fastreceiver(ch)
|
||||
select {
|
||||
case ch <- 5:
|
||||
}
|
||||
close(ch)
|
||||
time.Sleep(time.Millisecond)
|
||||
wg.wait()
|
||||
println("did send one")
|
||||
|
||||
// Test select with a single recv operation (transformed into chan recv).
|
||||
@@ -70,9 +115,12 @@ func main() {
|
||||
|
||||
// Test select recv with channel that has one entry.
|
||||
ch = make(chan int)
|
||||
wg.add(1)
|
||||
go func(ch chan int) {
|
||||
ch <- 55
|
||||
wg.done()
|
||||
}(ch)
|
||||
// not defined behavior, but we cant really fix this until select has been fixed
|
||||
time.Sleep(time.Millisecond)
|
||||
select {
|
||||
case make(chan int) <- 3:
|
||||
@@ -82,6 +130,7 @@ func main() {
|
||||
case n := <-make(chan int):
|
||||
println("unreachable:", n)
|
||||
}
|
||||
wg.wait()
|
||||
|
||||
// Test select recv with closed channel.
|
||||
close(ch)
|
||||
@@ -96,6 +145,7 @@ func main() {
|
||||
|
||||
// Test select send.
|
||||
ch = make(chan int)
|
||||
wg.add(1)
|
||||
go fastreceiver(ch)
|
||||
time.Sleep(time.Millisecond)
|
||||
select {
|
||||
@@ -105,9 +155,49 @@ func main() {
|
||||
println("unreachable:", n)
|
||||
}
|
||||
close(ch)
|
||||
wg.wait()
|
||||
|
||||
// Allow goroutines to exit.
|
||||
time.Sleep(time.Microsecond)
|
||||
// test non-concurrent buffered channels
|
||||
ch = make(chan int, 2)
|
||||
ch <- 1
|
||||
ch <- 2
|
||||
println("non-concurrent channel recieve:", <-ch)
|
||||
println("non-concurrent channel recieve:", <-ch)
|
||||
|
||||
// test closing channels with buffered data
|
||||
ch <- 3
|
||||
ch <- 4
|
||||
close(ch)
|
||||
println("closed buffered channel recieve:", <-ch)
|
||||
println("closed buffered channel recieve:", <-ch)
|
||||
println("closed buffered channel recieve:", <-ch)
|
||||
|
||||
// test using buffered channels as regular channels with special properties
|
||||
wg.add(6)
|
||||
ch = make(chan int, 2)
|
||||
go send(ch)
|
||||
go send(ch)
|
||||
go send(ch)
|
||||
go send(ch)
|
||||
go receive(ch)
|
||||
go receive(ch)
|
||||
wg.wait()
|
||||
close(ch)
|
||||
var count int
|
||||
for range ch {
|
||||
count++
|
||||
}
|
||||
println("hybrid buffered channel recieve:", count)
|
||||
}
|
||||
|
||||
func send(ch chan<- int) {
|
||||
ch <- 1
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func receive(ch <-chan int) {
|
||||
<-ch
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func sender(ch chan int) {
|
||||
@@ -119,15 +209,18 @@ func sender(ch chan int) {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func sendComplex(ch chan complex128) {
|
||||
ch <- 7 + 10.5i
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func fastsender(ch chan int, n int) {
|
||||
ch <- n
|
||||
ch <- n + 1
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func slowreceiver(ch chan int) {
|
||||
@@ -153,6 +246,7 @@ func fastreceiver(ch chan int) {
|
||||
sum += n
|
||||
}
|
||||
println("sum:", sum)
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func iterator(ch chan int, top int) {
|
||||
@@ -160,6 +254,7 @@ func iterator(ch chan int, top int) {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
wg.done()
|
||||
}
|
||||
|
||||
func selectDeadlock() {
|
||||
@@ -174,4 +269,5 @@ func selectNoOp() {
|
||||
default:
|
||||
}
|
||||
println("after no-op")
|
||||
wg.done()
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -25,3 +25,9 @@ select n from chan: 55
|
||||
select n from closed chan: 0
|
||||
select send
|
||||
sum: 235
|
||||
non-concurrent channel recieve: 1
|
||||
non-concurrent channel recieve: 2
|
||||
closed buffered channel recieve: 3
|
||||
closed buffered channel recieve: 4
|
||||
closed buffered channel recieve: 0
|
||||
hybrid buffered channel recieve: 2
|
||||
|
||||
Reference in New Issue
Block a user