并发编程学习收藏

协程非常简单,直接函数前加一个go就可以了

阻塞运行 #

package main
func task()  {
	for {
		println("task func")
	}
}
func main() {
	task()
	println("main over")

}

执行结果一直运行输出:

task func
task func
....

开启一个协程 #

package main

func task()  {
	for {
		println("task func")
	}
}
func main() {
	go task()
	println("main over")

}

输出内容:

main over

这个输出内容不确定,如果开启协程速度快于main,会输出

main over
task func

出现上面的问题是因为主程序退出,启动的协程也自动关闭

设置主程序的执行时间 #

主程序设置

func task()  {
	for {
		println("task func")
	}
}
func main() {
	//debug()
	go task()

	time.Sleep(time.Millisecond * 2) //延迟2毫秒后继续运行
	println("main over")
}

输出内容

task func
task func
...
main over
task func //有的时候会出现,主要是看主程序执行完成,回收goroutine的时间点

如果想最后输出一定要main over可以通过defer关键字

func main() {
	//debug()
	go task()

    //延迟2毫秒后继续运行
	time.Sleep(time.Millisecond * 2) 
    
    //or 通过接收2毫秒延迟channel通知 同上
    <-time.After(time.Millisecond * 2)
    
	defer println("main over")
    
    //多个延迟执行可以 defer延迟执行,释放资源,关闭文件,关闭连接,关闭channel等
    //defer println("main over 1")
    //defer println("main over 2")
    //也可以通过封装一个匿名函数中
    //defer func() {
	//	println("main over")
	//}()
}
  • 通过defer 延迟执行
  • defer 可以写多行
  • defer 可以运行匿名函数,函数内写释放资源的代码

主程序一直执行 #

func main() {
	//debug()
	go task()

	time.Sleep(time.Millisecond * 2) //延迟2毫秒

	defer println("main over")
	
    //阻塞的死循环
	for {

	}
    //或通过select接收或发送channel进行阻塞 同上
    select {
	}
    
    //或者通过中断信号接收后停止运行
    sig := make(chan os.Signal)
	signals := []os.Signal{syscall.SIGINT,syscall.SIGQUIT}
	signal.Notify(sig,signals...)
	//同上 SIGINT发送INTR字符(Ctrl+C)触发 SIGQUIT发送QUIT字符(Ctrl+/)触发
	//signal.Notify(sig,syscall.SIGQUIT,syscall.SIGINT)
	<-sig
	//同上
	//select {
	//case <-sig:
	//	
	//}
}
  • 方法1 通过for死循环
  • 通过select case接收和发送信道
  • 通过用户发送信号

子协程和主程序通信 #

func task() {
	i := 0
	for {
		i++
		println("task func",i)
		if i == 200 {
			quit <- true
			break //如果不加break,在主程序接收quit通知时i会继续打印201 202 ...
		}
	}
	close(quit)
}

var quit = make(chan bool)

func main() {
	go task()
	<- quit
	defer println("main over")
}

改造上面程序,通过形参的方式传递channel

  • goroutine中处理业务,处理中断出,发送quit的通知channel

  • 主程序阻塞等待 <- quit,接收到信息后继续下面执行

//发送通知
func task(q chan <- bool) {
	i := 0
	for {
		i++
		println("task func",i)
		if i == 200 {
			q <- true //发送退出通知
			break
		}
	}
}


func main() {
	quit := make(chan bool)
	go task(quit)
	<- quit //等待接收
	defer println("main over")
}

channel不是全局变量而是局部变量,可以通过形参的形式传递

信道的发送和接收 #

//通过发送
func send(ch chan <- int) {
	i := 0
	for {
		i++
		println("task func",i)
		ch <- i
	}
	defer close(ch) //能关闭发送channel
}

//接收
func receive(ch <-chan int)  {
	for c := range ch {
		println(c)
	}
}


func main() {
	ch := make(chan int)
	go send(ch)
	go receive(ch)

	time.Sleep(time.Millisecond * 5)

	defer func() {
		println("main over")
	}()
}

如果传递参数未标明是接收信道还是发送信道,就可以在接收channel中进行lclose

func send(ch chan int) {
	i := 0
	for {
		i++
		println("task func", i)
		ch <- i
	}
}

func receive(ch chan int)  {
	for c := range ch {
		println(c)
	}

	defer close(ch)
}