Go 并发 -- 协程

这是『就要学习 Go 语言』系列的第 21 篇分享文章markdown

并发与并行

提到并发,相信你们还听过另外一个概念 -- 并行。我先给你们介绍下这二者之间的区别,再来说 Go 语言的并发。多线程

并行其实很好理解,就是同时执行的意思,在某一时间点可以执行多个任务。 想达到并行效果,最简单的方式就是借助多线程或多进程,这样才可在同一时刻执行多个任务。单线程是永远没法达到并行状态的。 并发是在某一时间段内能够同时处理多个任务。咱们一般会说程序是并发设计的,也就是说它容许多个任务同时执行,这个同时指的就是一段时间内。单线程中多个任务以间隔执行实现并发。 能够说,多线程或多进程是并行的基础,但单线程也经过协程实现了并发。并发

举个常见的例子,一台单核电脑能够下载、听音乐,实际上这两个任务是这样执行的,只不过这两个任务切换时间短,给人的感受是同时执行的。 函数

并发
一台多核电脑的任务执行就是像下面这种图显示的同样:
并行
能够看到,同一时刻能执行多个任务。这种任务执行方式才是真正的并行。

Go 经过协程实现并发,协程之间靠信道通讯,本篇文章先给你们介绍协程的使用,后面再写信道。oop

协程

协程(Goroutine)能够理解成轻量级的线程,但与线程相比,它的开销很是小。所以,Go 应用程序一般能并发地运行成千上万的协程。 Go 建立一个协程很是简单,只要在方法或函数调用以前加关键字 go 便可。学习

func printHello() {
	fmt.Println("hello world goroutine")
}

func main() {
	go printHello()    // 建立了协程
	fmt.Println("main goroutine")
}
复制代码

输出:spa

main goroutine
复制代码

上面代码,第 6 行使用 go 关键字建立了协程,如今有两个协程,新建立的协程和主协程。printHello() 函数将会独立于主协程并发地执行。 是的,你没有看错,程序的输出就是这样,不信?你能够实际运行下程序。你惊讶的是,printHello() 函数为何没有输出,到底发生了什么? 当协程建立完毕以后,主函数当即返回继续执行下一行代码,不像函数调用,须要等函数执行完成。主协程执行完毕,程序便退出,printHello 协程随即也退出,便不会有输出。.net

修改下代码:线程

func printHello() {
	fmt.Println("hello world goroutine")
}

func main() {
	go printHello()
	time.Sleep(1*time.Second)
	fmt.Println("main goroutine")
}
复制代码

协程建立完成以后,main 协程先休眠 1s,预留给 printHello 协程执行的时间,因此此次输出:设计

hello world goroutine
main goroutine
复制代码

建立多个协程

上一节就提到,能够建立多个协程,来看下例子:

func printNum() {
	for i := 1; i <= 5; i++ {
		time.Sleep(20 * time.Millisecond)
		fmt.Printf("%d ", i)
	}
}
func printChacter() {
	for i := 'a'; i <= 'e'; i++ {
		time.Sleep(40 * time.Millisecond)
		fmt.Printf("%c ", i)
	}
}
func main() {
	go printNum()
	go printChacter()
	time.Sleep(3*time.Second)
	fmt.Println("main terminated")
}
复制代码

上面的代码,除主协程以外,新建立了两个协程:printNum 协程和 printChacter 协程。printNum 协程每隔 20 毫秒输出 5 个数,printChacter 协程每隔 40 毫秒输出字母。主协程建立完这两个协程以后休眠 1s,等待其余协程执行完成。 程序输出(你的输出可能跟个人不同):

1 a 2 3 b 4 5 c d e main terminated
复制代码

在这里插入图片描述

话说回来,经过加 time.Sleep() 函数等待协程执行完成是一种“黑科技”。在实际生产环境中,无论咱们是否知道其余协程执行完成须要多少时间,都不能在主协程中添加随机睡眠调用等待其余协程执行完成。那怎么办?Go 给咱们提供了信道,当协程执行完毕,可以通知到主协程,还可以实现协程间通讯。下节课咱们来讨论一下。

匿名协程

在函数那篇文章讲过,存在匿名函数,经过关键字 go 调用匿名函数就是匿名协程。咱们修改以前的例子:

func main() {
	go func() {
		fmt.Println("hello world goroutine")
	}()
	time.Sleep(1*time.Second)
	fmt.Println("main goroutine")
}
复制代码

输出结果跟以前的同样。

但愿这篇文章给你带来收获,Good Day !


(全文完)

原创文章,若需转载请注明出处!
欢迎扫码关注公众号「Golang来啦」或者移步 seekload.net ,查看更多精彩文章。

给你准备了学习 Go 语言相关书籍,公号后台回复【电子书】领取!

公众号二维码
相关文章
相关标签/搜索