go goroutine

进程和线程react

  • 进程是程序在操做系统中的一次执行过程,系统进行资源分配和调度的 一个独立单位。
  • 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更 小的能独立运行的基本单位。
  • 一个进程能够建立和撤销多个线程;同一个进程中的多个线程之间能够并发执行。

 

 

并发和并行git

  • 多线程程序在一个核的cpu上运行,就是并发
  • 多线程程序在多个核的cpu上运行,就是并行

 

协程和线程github

  • 协程:独立的栈空间,共享堆空间,调度由用户本身控制,本质上有点相似于 用户级线程,这些用户级线程的调度也是本身实现的。
  • 线程:一个线程上能够跑多个协程,协程是轻量级的线程。

能够说,协程与线程主要区别是它将再也不被内核调度,而是交给了程序本身而线程是将本身交给内核调度,因此也不难理解golang中调度器的存在。golang

示例:多线程

package main

import "fmt"
import "time"

func test() {
	var i int
	for {
		fmt.Println(i)
		time.Sleep(time.Second)
		i++
	}
}

func main() {
	go test()
	for {
		fmt.Println("i' running in main")
		time.Sleep(time.Second)
	}
}

 

goroutine调度模型并发

golang的goroutine是如何实现的?  知乎上一篇介绍文章。ui

  • M: 表明真正的内核OS线程,和POSIX里的thread差很少,真正干活的人。
  • G: 表明一个goroutine,它有本身的栈,instruction pointer和其余信息(正在等待的channel等等),用于调度。
  • P: 表明调度的上下文,能够把它看作一个局部的调度器,使go代码在一个线程上跑,它是实现从N:1到N:M映射的关键。

图中看,有2个物理线程M,每个M都拥有一个context(P),每个也都有一个正在运行的goroutine。
P的数量能够经过GOMAXPROCS()来设置,它其实也就表明了真正的并发度,即有多少个goroutine能够同时运行。
图中灰色的那些goroutine并无运行,而是出于ready的就绪态,正在等待被调度。P维护着这个队列(称之为runqueue)。

图中看到,当一个OS线程M0陷入阻塞时,P转而在OS线程M1上运行。调度器保证有足够的线程来运行因此的context P。spa

 三者关系的宏观的图为:操作系统

 

 

如何设置golang运行的cpu核数线程

package main

import (
	"fmt"
	"runtime"
)

func main() {
	num := runtime.NumCPU()
	runtime.GOMAXPROCS(num)
	fmt.Println(num)
}

备注:go1.8版本以后能够不用设置,默认使用全部CPU核数。

 

锁示例:

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中使用recover

应用场景,若是某个goroutine panic了,并且这个goroutine里面没有 捕获(recover),那么整个进程就会挂掉。因此,好的习惯是每当go产 生一个goroutine,就须要写下recover。

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 < 2; i++ {
		go calc()
	}

	time.Sleep(time.Second * 10000)
}

 

Go并发原理 https://i6448038.github.io/2017/12/04/golang-concurrency-principle/

Golang非CSP并发模型外的其余并行方法总结 https://i6448038.github.io/2018/12/18/Golang-no-csp/

相关文章
相关标签/搜索