进程和线程

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

并发和并行

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

协程和线程

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

可以说,协程与线程主要区别是它将不再被内核调度,而是交给了程序自己而线程是将自己交给内核调度,所以也不难理解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是如何实现的?  知乎上一篇介绍文章。

  • 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。

三者关系的宏观的图为:

如何设置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/

go goroutine的更多相关文章

  1. TODO:Go语言goroutine和channel使用

    TODO:Go语言goroutine和channel使用 goroutine是Go语言中的轻量级线程实现,由Go语言运行时(runtime)管理.使用的时候在函数前面加"go"这个 ...

  2. Golang之chan/goroutine(转)

    原文地址:http://tchen.me/posts/2014-01-27-golang-chatroom.html?utm_source=tuicool&utm_medium=referra ...

  3. 【Go入门教程7】并发(goroutine,channels,Buffered Channels,Range和Close,Select,超时,runtime goroutine)

    有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行. goroutine goroutine是Go并行设计的核心.goro ...

  4. goroutine

    Go语言从诞生到普及已经三年了,先行者大都是Web开发的背景,也有了一些普及型的书籍,可系统开发背景的人在学习这些书籍的时候,总有语焉不详的感觉,网上也有若干流传甚广的文章,可其中或多或少总有些与事实 ...

  5. 进程、线程、轻量级进程、协程与 go 的 goroutine【转载+整理】

    本文内容 进程 线程 协程 Go 中的 goroutine 参考资料 最近,看一些文章,提到"协程"的概念,心想,进程,线程,协程,前两个很容易,任何一本关于操作系统的书都有说,开 ...

  6. Golang控制goroutine的启动与关闭

    最近在用golang做项目的时候,使用到了goroutine.在golang中启动协程非常方便,只需要加一个go关键字: go myfunc(){ //do something }() 但是对于一些长 ...

  7. [转载] goroutine背后的系统知识

    原文: http://www.sizeofvoid.net/goroutine-under-the-hood/ 文章写的非常好, 对内部原理解释的非常清楚, 是我喜欢的风格, 感谢作者的精彩文章. = ...

  8. golang的goroutine与channel

    Golang的goroutine是非抢占式的, 令人相当蛋疼! 有痛不能呻吟...只能配合channel在各goroutine之间传递信号来实现抢占式, 而这形成了golang最灵活与最具性能的核心. ...

  9. [golang学习] goroutine调度

    这两天有些闲功夫, 学习下golang, 确实非常简洁. 不过有些缺憾. 在我的测试中. golang的调度(goroutine)似乎不是非常好. func say(k int) { fmt.Prin ...

  10. 进程、线程、轻量级进程、协程和go中的Goroutine

    进程.线程.轻量级进程.协程和go中的Goroutine 那些事儿电话面试被问到go的协程,曾经的军伟也问到过我协程.虽然用python时候在Eurasia和eventlet里了解过协程,但自己对协程 ...

随机推荐

  1. jdk6使用WebSocket

    pom.xml <dependency> <groupId>org.java-websocket</groupId> <artifactId>Java- ...

  2. Java自定义线程池-记录每个线程执行耗时

    ThreadPoolExecutor是可扩展的,其提供了几个可在子类化中改写的方法,如下: protected void beforeExecute(Thread t, Runnable r) { } ...

  3. python optparser模块

    python的内置模块中对于命令行的解析模块共两个getopt 和 optparse .不过getopt过于简单,往往不能满足需求.此时可以使用optparse模块.这个模块相对于getopt更新,功 ...

  4. python之旅5【第五篇】

    装饰器详解 函数刚开始不解析内部,只是放进内存 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 1 下面以一个函数开始,理解下面 ...

  5. Codeforces Round #454 Div. 1

    B:考虑2*m怎么构造.因为要求相邻的数不能再相邻,容易想到黑白染色之类的东西,考虑染个色然后大概把黑点扔一边白点扔一边.显然m<=3时无解.对m>4,m为偶数时,如1 2 3 4 5 6 ...

  6. Codeforces264 B. Good Sequences

    Codeforces题号:#264B 出处: Codeforces 主要算法:DP 难度:4.8 思路分析: 这题DP太难了…… 最终的解法是,令f[i]表示存在因子i的一个数作为子序列结尾的子序列的 ...

  7. Easy Finding POJ - 3740 (DLX)

    显然这是一道dfs简单题 或许匹配也能做 然而用了dancing links 显然这也是一道模板题 好的吧 调了一上午 终于弄好了模板 Easy Finding Time Limit: 1000MS ...

  8. hdu 2844 Coins (多重背包+二进制优化)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2844 思路:多重背包 , dp[i] ,容量为i的背包最多能凑到多少容量,如果dp[i] = i,那么代表 ...

  9. 如何使用JPQL写纯SQL语句

    使用JPQL,需要把SQL语句修改成类似HQL 语句.SQL 查询的是数据库,而JPQL 查询的是对象和属性,在语法上是有些不同的.对于有些用JPQL 无法写出来的查询,还是使用原生SQL写出来方便 ...

  10. Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)

    题意 给定一棵 \(n\) 个点的带点权树,以 \(1\) 为根, \(m\) 次询问,每次询问给出两个值 \(p, k\) ,求以下值: \(p\) 的子树中距离 \(p \le k\) 的所有点权 ...