基础知识

在学习golang的Goroutine和channel之前,先回顾一下最基本的并发知识

1s = 1000ms =1000000us = 1000000000ns

并行: 借助多核Cpu实现。

并发: 多个计算任务顺序执行,轮换使用cpu时间轮片

进程并发 :
程序 : 编译成功得到的二进制文件 占用 磁盘空间 。 死的
进程 : 运行起来程序。占用系统资源

线程并发:
线程:LWP轻量级的 进程。 最小的执行单位
进程:最小的系统资源分配单位

同步():
协同步调。规划先后顺序。
线程同步机制:
互斥锁(互斥量) :建议锁。拿到锁以后,才能访问数据,没有拿到锁的线程,阻塞等待。等待拿锁的线程释放锁。
读写锁: 一把锁(读属性、写属性)。写独占,读共享。写锁优先级高。

协程并发:
协程 (coroutine) 也叫清凉级线程
提高程序执行效率

Goroutine :go 程

创建与进程中。直接使用go关键词,放置于函数调用前面,产生一个go程 。并发。

下面是一个Goroutine的基本用法

package main

import (
    "fmt"
    "time"
)

func newTask() {
    i := 0
    for {
        i++
        fmt.Printf("new goroutine: i = %d\n", i)
        time.Sleep(1 * time.Second) //延时1s
    }
}

func main() {
    //创建一个 goroutine,启动另外一个任务
    go newTask()
    i := 0
    //main goroutine 循环打印
    for {
        i++
        fmt.Printf("main goroutine: i = %d\n", i)
        time.Sleep(1 * time.Second) //延时1s
    }
}

Goroutine的特性【特性】:
主go程结束,子go程随之退出。

runtime.Gosched() :出让当前go程序所占用的cpu时间片。当再次获得cpu时候,从出让位置继续恢复。

runtime.Goexit() :
return :返回当前函数调用到调用者那里去。return之前的defer注册生效
Goexit()结束调用该函数的当前go程。Goexit()之前注册的defer都生效

runtime.GOMAXPROCS(1) //将cpu设置为单核
设置当前进程使用的最大cpu核数。返回上一次调用成功的设置值。首次调用返回默认值

runtime.GOROOT

channel :

这是一种数据类型,对应一个 “管道”  (通道)  
goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。goroutine奉行--通过通信来共享内存,而不是共享内存来通信
引用类型channel可用于多个goroutine通讯。其内部实现了同步,确保并发安全

channel 的定义:make(chan 在channel中传递的参数类型,容量) 容量 = 0: 无缓冲channel,容量>0:有缓冲channel
eg: make(chan int) 或 make(chan string ,0)

补充知识点 :每当有一个进程启动时,系统会自动打开三个文件:标准输入、标准输出、标准错误。 ----stdin、stdout、stderr
当运行结束收,操作系统自动关闭三个文件

下面是channel的一个基本应用(打印)

package main

import (
	"fmt"
	"time"
)

func printer(s string){
	for _,ch:= range s {
		fmt.Printf("%c",ch)
		time.Sleep(300*time.Millisecond)
	}
}

//全局定义channel,用来完成数据同步
var channel = make(chan int)

//定义两个人使用打印机
func person1(){      //person先执行

	printer("hello")
	channel <-  675    //只要类型符合,随便写什么 ,没人读之前,channel一直是阻塞
}
func person2(){         //person 后执行          <-channel    读数据,保证数据流向
	<-channel
	printer("world")
}

func main(){
	go person1() 
	go person2()
	for {
		;
	}
}

channel的两个端:
一端:写端(传入端) chan <-
另一端 :读端(传出端) <- chan

要求:读端和写端必须同时满足条件,才能在channel上进行数据流动,否则阻塞