test goroutine

This commit is contained in:
Bruce 2018-09-07 21:11:24 +08:00
parent f978e42036
commit f7dd9679d3
No known key found for this signature in database
GPG Key ID: C715526B381CAF28
10 changed files with 138 additions and 7 deletions

View File

@ -62,7 +62,7 @@ A curated collection of idiomatic design & application patterns for Go language.
| Pattern | Description | Status | | Pattern | Description | Status |
|:-------:|:----------- |:------:| |:-------:|:----------- |:------:|
| [N-Barrier](/concurrency/barrier.md) | Prevents a process from proceeding until all N processes reach to the barrier | ✘ | | [N-Barrier](/concurrency/barrier.md) | Prevents a process from proceeding until all N processes reach to the barrier | ✘ |
| [Bounded Parallelism](/concurrency/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ | | [Bounded Parallelism](/concurrency/bounded/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ |
| [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ | | [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ |
| [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ | | [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ |
| [Generators](/concurrency/generator.md) | Yields a sequence of values one at a time | ✔ | | [Generators](/concurrency/generator.md) | Yields a sequence of values one at a time | ✔ |

View File

@ -33,7 +33,7 @@
* [Semaphore](/synchronization/semaphore.md) * [Semaphore](/synchronization/semaphore.md)
* [Concurrency Patterns](/README.md#concurrency-patterns) * [Concurrency Patterns](/README.md#concurrency-patterns)
* [N-Barrier](/concurrency/barrier.md) * [N-Barrier](/concurrency/barrier.md)
* [Bounded Parallelism](/concurrency/bounded_parallelism.md) * [Bounded Parallelism](/concurrency/bounded/bounded_parallelism.md)
* [Broadcast](/concurrency/broadcast.md) * [Broadcast](/concurrency/broadcast.md)
* [Coroutines](/concurrency/coroutine.md) * [Coroutines](/concurrency/coroutine.md)
* [Generators](/concurrency/generator.md) * [Generators](/concurrency/generator.md)

View File

@ -40,11 +40,11 @@ type (
) )
type ( type (
eventObserver struct{ eventObserver struct {
id int id int
} }
eventNotifier struct{ eventNotifier struct {
// Using a map with an empty struct allows us to keep the observers // Using a map with an empty struct allows us to keep the observers
// unique while still keeping memory usage relatively low. // unique while still keeping memory usage relatively low.
observers map[Observer]struct{} observers map[Observer]struct{}
@ -84,10 +84,10 @@ func main() {
tick := time.NewTicker(time.Second).C tick := time.NewTicker(time.Second).C
for { for {
select { select {
case <- stop: case <-stop:
return return
case t := <-tick: case t := <-tick:
n.Notify(Event{Data: t.UnixNano()}) n.Notify(Event{Data: t.UnixNano()})
} }
} }
} }

View File

@ -1,6 +1,6 @@
# Bounded Parallelism Pattern # Bounded Parallelism Pattern
[Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelism](parallelism.md), but allows limits to be placed on allocation. [Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelism](../parallelism.md), but allows limits to be placed on allocation.
# Implementation and Example # Implementation and Example

View File

@ -0,0 +1,24 @@
package goroutine
import (
"fmt"
"testing"
"time"
)
func TestFiveGopherWithChan(t *testing.T) {
c := make(chan int)
for i := 0; i < 5; i++ {
go sleepyGopherWithChan(i, c)
}
for i := 0; i < 5; i++ {
gopherID := <-c
fmt.Println("gopher ", gopherID, " has finished sleeping")
}
}
func sleepyGopherWithChan(id int, c chan int) {
time.Sleep(2 * time.Second)
fmt.Println("... ", id, " snore ...")
c <- id
}

View File

@ -0,0 +1,25 @@
package goroutine
import (
"fmt"
"testing"
"time"
)
func TestOneGopher(t *testing.T) {
go sleepyGopher(1)
time.Sleep(3 * time.Second)
}
func TestFiveGopher(t *testing.T) {
c := make(chan int)
for i := 0; i < 5; i++ {
go sleepyGopherWithChan(i, c)
}
time.Sleep(3 * time.Second)
}
func sleepyGopher(id int) {
time.Sleep(2 * time.Second)
fmt.Println("... ", id, " snore ...")
}

View File

@ -0,0 +1,32 @@
package goroutine
import (
"fmt"
"sync"
"testing"
"time"
)
func TestWaitGophers(t *testing.T) {
var gophers = []string{"tom", "peter", "john", "brown"}
var waitGroup sync.WaitGroup
waitGroup.Add(len(gophers))
for i := 0; i < len(gophers); i++ {
go func(wg *sync.WaitGroup, name string) {
sleepyGopherSnore(name)
wg.Done()
}(&waitGroup, gophers[i])
}
waitGroup.Wait()
fmt.Println("All done")
}
func sleepyGopherSnore(name string) {
fmt.Println(name, ": ... start snore")
time.Sleep(2 * time.Second)
fmt.Println(name, ": ... snore")
}

View File

@ -0,0 +1,11 @@
package goroutine
import "testing"
// A deadlock happens when a group of goroutines are waiting for each other and none of them is able to proceed.
// The program will get stuck on the channel send operation waiting forever for someone to read the value.
// Go is able to detect situations like this at runtime.
func TestDeadlock(t *testing.T) {
c := make(chan int)
<-c
}

View File

@ -0,0 +1,39 @@
package goroutine
import (
"fmt"
"strings"
"testing"
)
func sourceGopher(downstream chan string) {
for _, v := range []string{"hello world", "a bad apple", "goodbye all"} {
downstream <- v
}
close(downstream)
}
func filterGopher(upstream, downstream chan string) {
for item := range upstream {
fmt.Println("filter ", item)
if !strings.Contains(item, "bad") {
downstream <- item
}
}
}
func printGopher(upstream chan string) {
for item := range upstream {
fmt.Println("print ", item)
}
}
// Pipeline source->filter->print
func TestPipeline(t *testing.T) {
c0 := make(chan string)
c1 := make(chan string)
go sourceGopher(c0)
go filterGopher(c0, c1)
printGopher(c1)
}