- goroutine
package main
import (
"fmt"
"time"
)
/*
goroutine 類協程{
定義{
任何函數只需加上go就能送給調度器運行
不需要在定義時區分是否時異步函數
調度器在合適的點進行切換
使用 -race來檢測數據訪問衝突
}
goroutine可能的切換點{
1.I/O,select
2.channel
3.等待鎖
4.函數調用(有時)
5.runtime.Gosched() //在某個點願意交出控制權
6.以上只是參考,不能保證切換,不能保證在其他地方不切換
}
內部結構{
調度器
線程{
goroutine*n
}
}
}
coroutine(協程){
輕量級"線程"{
非搶佔式多任務處理,由協程主動交出控制權
編譯器/解釋器/虛擬機層面的多任務
多個協程可能在一個或多個線程上運行
}
子程序是協程的一個特例{
普通函數{
線程{
main->doWork
}
}
協程{
線程(可能是多個線程,底層實現不用管){
main<->doWork 有一個通道,數據可以雙向流通,控制權也可雙向流通
}
}
}
}
*/
func main() {
// var a [10]int
for i := 0; i < 1000; i++ {
go func(i int) { // go run -race test.go 檢測數據訪問衝突 rece condition
for {
fmt.Printf("Hello from"+"goroutine %d \n", i)
// a[i]++
// runtime.Gosched() // 很少用到
}
}(i)
}
time.Sleep(time.Minute)
// fmt.Println(a)
}
- channel.go
package main
import (
"fmt"
"time"
)
/*
channel{
包含{
goroutine <= channel => goroutine * n
調度器
}
理論基礎{
communication Sequential Process(CSP模型)
不要通過共享內存來通信,通過通信來共享內存
}
}
*/
func worker(id int, c chan int) {
for n := range c { // 接收完畢 關閉1
// n, ok := <-c // 接收完畢 關閉2
// if !ok {
// break
// }
fmt.Printf("Worker %d received %d \n", id, n)
}
}
func createWorker(id int) chan<- int {
c := make(chan int)
go worker(id, c)
return c
}
func chanDemo() {
// var c chan int // 只是定義 沒有開闢內存空間 c == nil
var channels [10]chan<- int
for i := 0; i < 10; i++ {
channels[i] = createWorker(i) // 開闢內存空間
}
for i := 0; i < 10; i++ {
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++ {
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
}
func bufferedChannel() {
c := make(chan int, 3) // 新建一個大小爲3的緩衝區
go worker(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
time.Sleep(time.Millisecond) //
}
func channelClose() {
// 永遠是發送方來close
c := make(chan int, 3) // 新建一個大小爲3的緩衝區
go worker(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
close(c)
// time.Sleep(time.Millisecond)
}
func main() {
fmt.Println("Channel as first-class citizen")
chanDemo()
fmt.Println("Buffered channel")
bufferedChannel()
fmt.Println("Channel close and range")
channelClose()
}
- done.go
package main
import (
"fmt"
"sync"
)
/*
使用WaitGroup
*/
func doWorker(id int, w worker) {
for n := range w.in { // 接收完畢 關閉1
fmt.Printf("Worker %d received %c \n", id, n)
w.done()
}
}
type worker struct {
in chan int
// done chan bool
// wg *sync.WaitGroup
done func()
}
func createWorker(id int, wg *sync.WaitGroup) worker {
w := worker{
in: make(chan int),
done: func() { wg.Done() },
}
go doWorker(id, w)
return w
}
func chanDemo() {
var wg sync.WaitGroup
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker(i, &wg)
}
// wg.Add(20)
for i, worker := range workers {
worker.in <- 'a' + i
wg.Add(1)
}
for i, worker := range workers {
worker.in <- 'A' + i
wg.Add(1)
}
wg.Wait()
// wait for all of them
// for _, worker := range workers {
// <-worker.done
// }
}
func main() {
chanDemo()
}
- select.go
package main
import (
"fmt"
"math/rand"
"time"
)
func generator() chan int {
out := make(chan int)
go func() {
i := 0
for {
time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond)
out <- i
i++
}
}()
return out
}
func worker(id int, c chan int) {
for n := range c { // 接收完畢
time.Sleep(time.Second)
fmt.Printf("Worker %d received %d \n", id, n)
}
}
func createWorker(id int) chan<- int {
c := make(chan int)
go worker(id, c)
return c
}
func main() {
var c1, c2 = generator(), generator() // c1 and c2 == nil
var worker = createWorker(0)
var values []int
// 從啓動程序過去的時間
tm := time.After(10 * time.Second)
// 每過多長時間
tick := time.Tick(time.Second)
for {
// nil channel 有值的時候纔會初始化
var activeWorker chan<- int
var activeValue int
if len(values) > 0 {
activeWorker = worker
activeValue = values[0]
}
select {
case n := <-c1:
values = append(values, n)
case n := <-c2:
values = append(values, n)
case activeWorker <- activeValue:
values = values[1:]
// case n := <-c1:
// fmt.Println("Received from c1:", n)
// case n := <-c2:
// fmt.Println("Received from c2:", n)
// 非阻塞式從chan獲取值
// default:
// fmt.Println("No value received")
// 每次執行select 的時間 相鄰兩個請求時間的time out
case <-time.After(800 * time.Millisecond):
fmt.Println("time out")
// 反應系統的狀態
case <-tick:
fmt.Println("queue len = ", len(values))
// 總的時間來確定程序時常
case <-tm:
fmt.Println("bye")
return
}
}
}
- atomic
package main
import (
"fmt"
"sync"
"time"
)
type atomicInt struct {
value int
lock sync.Mutex
}
func (a *atomicInt) increment() {
a.lock.Lock()
defer a.lock.Unlock()
a.value++
}
func (a *atomicInt) get() int {
a.lock.Lock()
defer a.lock.Unlock()
return a.value
}
func main() {
var a atomicInt
a.increment()
go func() {
a.increment()
}()
time.Sleep(time.Millisecond)
fmt.Println(a.get())
}