A. 進程是程序在操做系統中的一次執行過程,系統進行資源分配合調度的一個獨立單位python
B. 線程是進程的一個執行實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。golang
C. 一個進程能夠建立和撤銷多個線程:同一個進程中的多個線程之間能夠併發執行。json
A. 多線程程序在一個核的cpu上運行,就是併發緩存
B. 多線程程序在多個核的cpu上運行,就是並行安全
協程:獨立的棧空間,共享棧空間,調度由用戶本身控制,本質上有點相似於用戶級線程,這些用戶級線程的調度也是本身實現的多線程
線程:一個線程上能夠拍多個協程, 協程是輕量級的線程併發
package main import ( "fmt" "time" ) func test() { var i int for { fmt.Println(i) time.Sleep(time.Second) i++ } } func main() { go test() time.Sleep(time.Second * 10) // for { // fmt.Println("i' running in main") // time.Sleep(time.Second) // } }
package main import ( "fmt" "sync" "time" ) type task struct { n int } var ( m = make(map[int]uint64) lock sync.Mutex // 互斥鎖 ) func calc(t *task) { var sum uint64 sum = 1 for i := uint64(1); i < uint64(t.n); i++ { sum *= i } fmt.Println(t.n, sum) lock.Lock() m[t.n] = sum lock.Unlock() } func main() { for i := 0; i < 16; i++ { t := &task{n: i} go calc(t) } time.Sleep(time.Second * 10) lock.Lock() for k, v := range m { fmt.Printf("%d! = %v\n", k, v) } lock.Unlock() }
a. 全局變量和鎖同步app
b. Channelide
a. 相似unix中管道(pipe)函數
b. 先進先出
c. 線程安全,多個goroutine同時訪問,不須要de加鎖
d. channel是有類型的,一個整數的channel只能存放整數
var 變量名 chan 類型 var test chan int var test chan string var test chan map[string]string var test chan stu var test chan *stu
使用make進行初始化,好比:
var test chan int test = make(chan int, 10) var test chan string test = make(chan string, 10)
1. 從channel讀取數據
var testChan chan int testChan = make(chan int, 10) var a int a = <- testChan
2. 從channel寫入數據
var testChan chan int testChan = make(chan int, 10) var a int = 10 testChan <- a
package main import ( "fmt" "time" ) func write(ch chan int) { for i := 0; i < 100; i++ { ch <- i fmt.Println("put data: ", i) } } func read(ch chan int) { for { var b int b = <-ch fmt.Println(b) time.Sleep(time.Second) } } func main() { intChan := make(chan int, 10) go write(intChan) go read(intChan) time.Sleep(time.Second * 10) }
1. 以下所示,testChan 只能放一個元素
testChan := make(chan int) var a int a = <- testChan
2. 以下所示,testChan是帶緩衝區的chan,一次能夠放10個元素
testChan = make(chan int, 10) var a int testChan <- a
package main import ( "fmt" ) func send(ch chan<- int, exitChan chan struct{}) { for i := 0; i < 10; i++ { ch <- i } close(ch) var a struct{} exitChan <- a } func recv(ch <-chan int, exitChan chan struct{}) { for { v, ok := <-ch if !ok { break } fmt.Println(v) } var a struct{} exitChan <- a } func main() { var ch chan int ch = make(chan int, 10) exitChan := make(chan struct{}, 2) go send(ch, exitChan) go recv(ch, exitChan) var total = 0 for _ = range exitChan { total++ if total == 2 { break } } }
package main import "fmt" type student struct { name string } func main() { var intChan chan int intChan = make(chan int, 10) intChan <- 10 var stringChan chan map[string]string stringChan = make(chan map[string]string, 10) m := make(map[string]string, 16) m["stu01"] = "001" m["stu01"] = "002" stringChan <- m var stuChan chan *student stuChan = make(chan *student, 10) stu := student{name: "stud01"} stuChan <- &stu var stuInterChan chan interface{} stuInterChan = make(chan interface{}, 10) stu1 := student{name: "stu01"} stuInterChan <- &stu1 var stu01 interface{} stu01 = <-stuInterChan fmt.Println(stu01) var stu02 *student stu02, ok := stu01.(*student) if !ok { fmt.Println("can not convert") return } fmt.Println(stu02) }
package main import ( "fmt" ) func calc(taskChan chan int, resChan chan int, exitChan chan bool) { for v := range taskChan { flag := true for i := 2; i < v; i++ { if v%i == 0 { flag = false break } } if flag { resChan <- v } } fmt.Println("exit") exitChan <- true } func main() { intChan := make(chan int, 1000) resultChan := make(chan int, 1000) exitChan := make(chan bool, 8) go func() { for i := 0; i < 100000; i++ { intChan <- i } close(intChan) }() for i := 0; i < 8; i++ { go calc(intChan, resultChan, exitChan) } // 等待全部的groutine所有退出 go func() { for i := 0; i < 8; i++ { <-exitChan fmt.Println("wait goroute", i, "exited") } close(resultChan) }() for v := range resultChan { fmt.Println(v) } }
package main import ( "fmt" ) func send(ch chan int, exitChan chan struct{}) { for i := 0; i < 10; i++ { ch <- i } close(ch) var a struct{} exitChan <- a } func recv(ch chan int, exitChan chan struct{}) { for { v, ok := <-ch if !ok { break } fmt.Println(v) } var a struct{} exitChan <- a } func main() { ch := make(chan int, 10) exitChan := make(chan struct{}, 2) go send(ch, exitChan) go recv(ch, exitChan) var total = 0 for _ = range exitChan { total++ if total == 2 { break } } }
package main import "fmt" func main() { var ch chan int ch = make(chan int, 1000) for i := 0; i < 1000; i++ { ch <- i } close(ch) for v := range ch { fmt.Println(v) } }
1. 使用內置函數close進行關閉,chan關閉以後,for range遍歷chan中已經放入的元素
2. 使用內置函數close進行關閉, chan關閉以後,沒有使用for range的寫法,須要判斷chan是否關閉。
示例
package main import "fmt" func main() { var ch chan int ch = make(chan int, 10) for i := 0; i < 10; i++ { ch <- i } close(ch) for { var b int b, ok := <-ch if ok == false { fmt.Println("chan is close") break } fmt.Println(b) } }
a. 只讀chan的聲明
var 變量的名字 <-chan int var readChan <-chan int
b.只寫chan的聲明
var 變量的名字 chan <- int var writeChan chan <- int
package main import ( "bufio" "fmt" "io" "os" ) func main() { file, err := os.Open("test.log") if err != nil { fmt.Println(err) return } defer file.Close() // 帶緩存區的文件讀寫 reader := bufio.NewReader(file) var line []byte for { data, prefix, err := reader.ReadLine() if err == io.EOF { break } line = append(line, data...) if !prefix { fmt.Printf("data: %s\n", string(data)) line = line[:] } } // fmt.Println(line) }
package main import ( "fmt" "time" ) func main() { var ch chan int ch = make(chan int, 10) ch2 := make(chan int, 10) go func() { var i int for { ch <- i time.Sleep(time.Second) ch2 <- i * i time.Sleep(time.Second) i++ } }() for { select { case v := <-ch: fmt.Println(v) case v := <-ch2: fmt.Println(v) case <-time.After(time.Second): fmt.Println("get data timeout") time.Sleep(time.Second) } // var b int // b = <-ch // fmt.Println(b) } }
package main import ( "runtime" "time" ) func main() { num := runtime.NumCPU() runtime.GOMAXPROCS(num - 1) for i := 0; i < 1024; i++ { go func() { for { select { case <-time.After(time.Microsecond): // fmt.Println("get data timeout") } } }() } time.Sleep(time.Second * 1000) }
package main import ( "fmt" "runtime" "time" ) func main() { num := runtime.NumCPU() runtime.GOMAXPROCS(num - 1) for i := 0; i < 16; i++ { go func() { for { t := time.NewTicker(time.Second) select { case <-time.After(time.Microsecond): fmt.Println("timeout") } t.Stop() } }() } time.Sleep(time.Second * 1000) }
package main import ( "fmt" "runtime" "time" ) func test() { defer func() { if err := recover(); err != nil { fmt.Println("panic:", err) } }() var m map[string]int m["stu"] = 100 } func calc() { for { fmt.Println("i'm calc") time.Sleep(time.Second) } } func main() { num := runtime.NumCPU() runtime.GOMAXPROCS(num - 1) go test() for i := 0; i < 100; i++ { go calc() } time.Sleep(time.Second * 1000) }
1.文件名必須以_test.go結尾
2. 使用Test開頭的函數名做爲測試函數
3. 測試案例
package main func add(a, b int) int { return a + b } func sub(a, b int) int { return a - b }
package main import ( "encoding/json" "io/ioutil" ) type student struct { Name string Sex string Age int } func (p *student) Save() (err error) { data, err := json.Marshal(p) if err != nil { return } err = ioutil.WriteFile("stu.dat", data, 0755) return } func (p *student) Load() (err error) { data, err := ioutil.ReadFile("stu.dat") if err != nil { return } err = json.Unmarshal(data, p) return }
package main import "testing" func TestAdd(t *testing.T) { r := add(2, 4) if r != 6 { t.Fatalf("add(2,4) error, expect:%d, actual:%d", 6, r) } t.Log("test add succ") } func TestSub(t *testing.T) { r := sub(2, 4) if r != -2 { t.Fatalf("sub(2,4) error, expect:%d, actual:%d", -2, r) } t.Logf("test sub succ") }
package main import "testing" func TestSave(t *testing.T) { stu := &student{ Name: "stu01", Sex: "man", Age: 10, } err := stu.Save() if err != nil { t.Fatalf("save student failed: err%v", err) } } func TestLoad(t *testing.T) { stu := &student{ Name: "stu01", Sex: "man", Age: 10, } err := stu.Save() if err != nil { t.Fatalf("save student failed: err%v", err) } stu2 := &student{} err = stu2.Load() if err != nil { t.Fatalf("load student failed,err: %v", err) } if stu.Name != stu2.Name { t.Fatalf("load student failed, Name not equal") } if stu.Age != stu2.Age { t.Fatalf("load student failed, Age not equal") } if stu.Sex != stu2.Sex { t.Fatalf("load student failed, Sex not equal") } }
package main