程序和線程
A。程序是程式在作業系統中的一次執行過程,系統進行資源配置設定和排程的一個獨立機關。
B。線程是程序的一個執行實體,是CPU排程和分派的基本機關,它是比程序更小的能獨立運作的基本機關。
C。一個程序可以建立和撤銷多個線程;同一程序中的多個線程之間可以并發執行。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iM4MjMwMWZjVmZykDMwMGM0YWM3EWZ1gTOkJTZzYTO18CXxEzLcVDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL5M3Lc9CX6MHc0RHaiojIsJye.png)
并發和并行
并發:多線程程式在一個核的cpu上運作
并行:多線程程式在多個核的cpu上運作
舉例。。一個媽給一個碗給多個小孩喂飯,,是并發
一個媽給每個小孩一人一個碗,就是并行
并發 并行
協程和線程
協程:獨立的棧空間,共享堆空間,排程由使用者自己控制,本質上有點類似于使用者級協程,這些使用者級線程的排程也是自己實作的。
線程:一個線程上可以跑多個協程,協程是輕量級的線程。
例子
package main
import (
"fmt"
"time"
)
func test() {
var i int
for {
fmt.Println(i)
time.Sleep(time.Second)
i++
}
}
func main() {
go test() //起一個協程執行test()
for {
fmt.Println("i : runnging in main")
time.Sleep(time.Second )
}
}
-
--
設定Golang運作的cpu核數。
1.8版本以上,預設跑多個核
package main
import (
"fmt"
"runtime"
)
func main() {
num := runtime.NumCPU()
runtime.GOMAXPROCS(num)
fmt.Println(num)
}
并發計算
package main
import (
"fmt"
"sync"
"time"
)
var (
m = make(map[int]uint64)
lock sync.Mutex
)
type task struct {
n int
}
func calc(t *task) {
var sum uint64
sum = 1
for i := 1; i < t.n; i++ {
sum *= uint64(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(10 * time.Second)
//lock.Lock()
//for k, v := range m {
// fmt.Printf("%d!=%v\n", k, v)
//}
//lock.Unlock()
}
Channel
channel概念
a。類似unix中的管道(pipe)
b.先進先出
c。線程安全,多個goroutine同時通路,不需要枷鎖
d。channel是有類型的,一個整數的channel隻能存整數
channel聲明
var name chan string
var age chan int
var mapchan chan map[string]string
var test chan student
var test1 chan *student
channel初始化
使用make進行初始化
var test chan int
test = make(chan int,10)
var test chan string
test=make(chan string,10)
channel基本操作
從channel讀取資料
var testChan chan int
testChan = make(chan int, 10)
var a int
a = <-testChan
-從channel寫入資料
var testChan chan int
testChan = make(chan int, 10)
var a int = 10
testChan <- a
第一個例子
package main
import "fmt"
type student struct {
name string
}
func main() {
var stuChan chan *student
stuChan = make(chan *student, 10)
stu := student{name: "stu001"}
stuChan <- &stu
var stu01 interface{}
stu01 = <-stuChan
var stu02 *student
stu02, ok := stu01.(*student)
if !ok {
fmt.Println("can not convert")
return
}
fmt.Println(stu02)
}
goroutine與channel
package main
import (
"fmt"
"time"
)
//起一個讀的協程
func write(ch chan int) {
for i := 0; i < 1000; i++ {
ch <- i
}
}
func read(ch chan int) {
for {
var b int
b = <-ch
fmt.Println(b)
}
}
func main() {
intChan := make(chan int, 10)
go write(intChan)
go read(intChan)
time.Sleep(10 * time.Second)
}
讀,取,字元串
package main
import (
"fmt"
"time"
)
func sendData(ch chan string) {
ch <- "Washington"
ch <- "Tripoli"
ch <- "London"
ch <- "Beijing"
ch <- "Tokio"
}
func getData(ch chan string) {
var input string
for {
input = <-ch
fmt.Println(input)
}
}
func main() {
ch := make(chan string)
go sendData(ch)
go getData(ch)
time.Sleep(3 * time.Second)
}
讀取字元串
Channel緩沖區
隻能放一個元素的testChan
var testChan chan int
testChan = make(chan int)
var a int
a = <-testChan
testChan是帶緩沖區的chan,一次可以放10個元素
var testChan chan int
testChan = make(chan int, 10)
var a int = 10
testChan <- a
-
package main
import (
"fmt"
"sync"
"time"
)
var (
m = make(map[int]uint64)
lock sync.Mutex
)
type task struct {
n int
}
func calc(t *task) {
var sum uint64
sum = 1
for i := 1; i < t.n; i++ {
sum *= uint64(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(10 * time.Second)
lock.Lock()
for k, v := range m {
fmt.Printf("%d!=%v\n", k, v)
}
lock.Unlock()
}
goroutine_lock
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 < 10000; i++ {
intChan <- i
}
close(intChan)
}()
for i := 0; i < 8; i++ {
go calc(intChan, resultChan, exitChan)
}
//等待所有計算的goroutine全部退出
go func() {
for i := 0; i < 8; i++ {
<-exitChan
fmt.Println("wait goroute", i, "exited")
}
close(resultChan)
}()
for v := range resultChan {
fmt.Println(v)
}
}
goroutine_sync
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
}
}
}
goroutine_sync2
檢測管道是否關閉
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)
}
}
如何關閉chan
1. 使用内置函數close進行關閉,chan關閉之後,for range周遊chan中
已經存在的元素後結束
2. 使用内置函數close進行關閉,chan關閉之後,沒有使用for range的寫法
需要使用,v, ok := <- ch進行判斷chan是否關閉
chan的隻讀和隻寫
隻讀的聲明
Var 變量的名字 <-chan int
Var readChan <- chan int
隻寫的聲明
Var 變量的名字 chan<- int
Var writeChan chan<- int
package main
import "fmt"
//隻寫chan
func send(ch chan<- int, exitChan chan struct{}) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
var a struct{}
exitChan <- a
}
//隻讀chan
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) //初始化chan
exitChan := make(chan struct{}, 2)
go send(ch, exitChan)
go recv(ch, exitChan)
var total = 0
for _ = range exitChan {
total++
if total == 2 {
break
}
}
}
隻讀隻寫示例chan
package main
import "fmt"
import "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)
}
}
}
chan不阻塞