进程和线程

进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。

线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

一个进程可以创建和撤销多个线程;同一个进程中的多个线程之间可以并发执行.

并发和并行

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

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

协程和线程

协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的

线程:一个线程上可以跑多个协程,协程是轻量级的线程。

goroutine调度模型

简单的例子

package main

import "fmt"
import "time" func test() {
var i int
for {
fmt.Println(i)
time.Sleep(time.Second*5)
i++
}
} func main() {
go test()
for {
fmt.Println("i' running in main")
time.Sleep(time.Second)
}
}

设置golang运行的cpu核数

go1.8版本以上默认设置了

package main

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

不同goroutine之间通讯

全局变量和锁同步

package main

import (
"fmt"
"time"
"sync"
) 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<20;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只能存放整数

var 变量名 chan 类型

var test chan int

var test chan string

var test chan map[string]string

var test chan stu

var test chan *stu

channel初始化

使用make进行初始化,比如:

var test chan int

test = make(chan int, 10)

var test chan string

test = make(chan string, 10)

从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

goroutine和channel相结合

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) //testChan是带缓冲区的chan,一次可以放10个元素
go write(intChan)
go read(intChan)//不读的话会引发阻塞
time.Sleep(10 * time.Second)
}

chan之间的同步

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"
)
//计算1000以内的素数
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, 100)
resultChan := make(chan int, 100)
exitChan := make(chan bool, 8) go func() {
for i := 0; i < 1000; 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)
_ = v
}
}

chan的关闭

1.使用内置函数close进行关闭,chan关闭之后,for range遍历chan中已经存在的元素后结束

2.使用内置函数close进行关闭,chan关闭之后,没有使用for range的写法需要使用,v, ok := <- ch进行判断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) //谨防死循环
}
}

for range遍历chan

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)
}
}

chan的只读和只写

a. 只读chan的声明

Var 变量的名字 <-chan int
Var readChan <- chan int

b. 只写chan的声明

Var 变量的名字 chan<- int
Var writeChan chan<- int

对chan进行select操作

select {
case u := <- ch1:
case e := <- ch2:
default:
}

下面是死锁了,阻塞了

package main

import "fmt"

func main()  {
var ch chan int
ch = make(chan int,10)
for i :=0;i<10;i++{
ch <- i
}
for {
var b int
b = <-ch
fmt.Println(b)
}
}

select解决阻塞

//@Time  : 2018/2/1 22:14
//@Author: ningxin
package main import (
"fmt"
"time"
) func main() {
var ch chan int
ch = make(chan int,10)
for i :=0;i<10;i++{
ch <- i
}
for {
select{
case v:= <-ch:
fmt.Println(v)
default:
fmt.Println("get data timeout")
time.Sleep(time.Second)
}
}
}

定时器的使用

package main

import (
"fmt"
"time"
)
func queryDb(ch chan int) { time.Sleep(time.Second)
ch <- 100
}
func main() {
ch := make(chan int)
go queryDb(ch)
t := time.NewTicker(time.Second) select {
case v := <-ch:
fmt.Println("result", v)
case <-t.C:
fmt.Println("timeout")
}
}

超时控制

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 <-t.C:
fmt.Println("timeout")
}
t.Stop()
}
}()
} time.Sleep(time.Second * 100)
}

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开发[八]goroutine和channel的更多相关文章

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

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

  2. goroutine 加 channel 代替递归调用,突破递归调用的层级限制

    package main import ( "fmt" "github.com/davecgh/go-spew/spew" "github.com/B ...

  3. Go基础--goroutine和channel

    goroutine 在go语言中,每一个并发的执行单元叫做一个goroutine 这里说到并发,所以先解释一下并发和并行的概念: 并发:逻辑上具备同时处理多个任务的能力 并行:物理上在同一时刻执行多个 ...

  4. goroutine和channel

    近期在学习golang的goroutine和channel时候有一些疑惑: 带缓冲的channel和不带缓冲的channel有什么区别? goroutine和主进程的有哪些影响和关系? 多个gorou ...

  5. .Net开发八年,坐标杭州,上个月换工作感觉现在.Net岗位很少,希望和同在杭州的同行们交流一下

    .Net开发八年,坐标杭州,中间做过2年Java, 目前新入职一家做防伪溯源的中型公司,200人左右, 之前在一家500人规模的软件公司工作过4年,后面2年工作过3家互联网创业公司, 上个月换工作感觉 ...

  6. [转帖]go 的goroutine 以及 channel 的简介.

    进程,线程的概念在操作系统的书上已经有详细的介绍.进程是内存资源管理和cpu调度的执行单元.为了有效利用多核处理器的优势,将进程进一步细分,允许一个进程里存在多个线程,这多个线程还是共享同一片内存空间 ...

  7. Go part 8 并发编程,goroutine, channel

    并发 并发是指的多任务,并发编程含义比较广泛,包含多线程.多进程及分布式程序,这里记录的并发是属于多线程编程 Go 从语言层面上支持了并发的特性,通过 goroutine 来完成,goroutine ...

  8. 从零开始实现ASP.NET Core MVC的插件式开发(八) - Razor视图相关问题及解决方案

    标题:从零开始实现ASP.NET Core MVC的插件式开发(八) - Razor视图相关问题及解决方案 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun ...

  9. Netty 源码解析(八): 回到 Channel 的 register 操作

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

随机推荐

  1. javascript 与node的 event-loop

    参考:https://juejin.im/post/5c337ae06fb9a049bc4cd218 https://github.com/forthealllight/blog/issues/5 h ...

  2. Android 组件化之路 资源冲突问题

    比如我现在有3个模块:app模块,user模块,me模块,其中app模块依赖user模块和me模块. 然后我在user模块和me模块的strings.xml中都定义了greet字符串: // user ...

  3. GUID在安全中作用及生成方法

    参考改进于http://blog.csdn.net/jcicheng/article/details/743934 全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装.在许多 ...

  4. 缺少库libresolv

    "_dns_free_resource_record", referenced from: -[xxxx processRecord:length:] in xxx.a(xxx.o ...

  5. String,StringBuilder和StringBuffer

    String 字符串常量,由String创建的字符内容,长度是不可改变,存放字符的数组被声明为final. 实际上String类操作字符串是通过建立一个StringBuffer,然后调用append( ...

  6. 修改docker自定义网桥后的默认网卡名称

    [root@docker2 ~]# docker  network   create  --subnet=10.10.10.0/24  docker1   #新键网桥docker142323044a4 ...

  7. 在VMware Vcenter添加一块网卡后,启动虚机找不到网卡,发现有一个ens38(redhat7.5)

    添加一块网卡后,启动虚机找不到网卡,发现有一个ens38 问题:新建虚拟机设置为一块网卡,时候在Vcenter再添加一块网卡,这个问题相信很多网友都见过,今天就来总结一下添加过程中的问题. 由于有以前 ...

  8. 索引介绍,转载自:https://tech.meituan.com/2014/06/30/mysql-index.html

    索引原理 除了词典,生活中随处可见索引的例子,如火车站的车次表.图书的目录等.它们的原理都是一样的,通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总 ...

  9. 【洛谷P1220】关路灯

    题目有点难描述,内容请直接看原题.. 题解: 可以发现人在关路灯时无论走什么样的路径,从宏观上来看被关的灯总是构成一段包含初始点的连续区间.比如要关掉下标为 l (l < st)的灯,则一定要先 ...

  10. 详解WebService开发中四个常见问题(1)

    详解WebService开发中四个常见问题(1)   WebService开发中经常会碰到诸如WebService与方法重载.循环引用.数据被穿该等等问题.本文会给大家一些很好的解决方法. AD:WO ...