本节源码位置https://github.com/golang-minibear2333/golang/blob/master/4.concurrent/4.1-goroutine/》以前我们通常使用多个线程实现,自己维护一个线程池,创建,销毁,适时分配资源。Go在并发方面为我们提供了语言级别的支持。goroutine和chan相互配合,决定了它先天的优势。GoroutineGoroutine的概念类似于线程。Go程序在运行时会被自动调度和管理。系统可以智能地将goroutine中的任务合理分配给CPU,让这些任务尽可能并发运行。与线程相比,它在使用上比线程更轻。一个数量级,你可以创建数十万或数百万而不用担心资源问题。使用withchan可以实现高并发,在goroutine之间传递数据更方便。如果访问同一个数据块,注意datarace问题,共享锁或者相互排斥锁的选择以及并发操作的数据同步(后面会讲到)实现方面,资源方面,栈内存大小线程数一般是固定的,一般为2MB。这个值虽然可以设置,但是太大浪费,太小容易用完,而且goroutine栈内存是可变的,初始一般2KB,可以根据需求扩展到1GB。因此,goroutine非常轻量,可以满足不同的需求。从调度的角度来看,线程的调度是由OS的内核完成的;线程的切换需要CPU寄存器和内存的数据交换,从而切换不同的线程上下文。触发方式是CPU时钟,而goroutine的调度是比较轻量级的,由自身的调度决定处理器来完成。协程和线程的关系有点类似于线程和进程的关系。创建和使用要创建goroutine,只需要在函数前加上go关键字即可。Go函数名(参数)看一个domefuncquickFun(){fmt.Println("maybeyoucan'sseeme!")}funcmain(){goquickFun()//创建了一个goroutinefmt.Println("hey")time.Sleep(time.Second)}goroutine和main主线程同时运行。主运行结束后,所有的协程都会被暴力终止,所以上面的程序多等了一秒。Go程序从main包的main()函数开始。当程序启动时,Go程序会为main()函数创建一个默认的goroutine。输出heymaybeyoucan'sseeme!是的,就这么简单,如果你的函数只是在这里使用,你也可以使用匿名函数来创建goroutines。funcmain(){gofunc(){fmt.Println("hello")}()time.Sleep(time.Second)//main操作结束会暴力终止所有协程,所以这里等待1秒}PS:和thread不同,goroutine没有唯一的id,所以我们没有办法专门q去对一个coroutine进行操作。goroutinegoroutine是Go语言并行设计的核心。goroutine是比线程更轻量级的实现,十几个goroutine可能底层就是几个线程。实际上,Go在运行时、系统调用等各个方面对goroutine的调度进行了封装和处理。要使用goroutine,只需在要执行的函数之前添加go关键字即可。当goroutine执行完后,Go语言立即返回,然后在不阻塞主线程的情况下执行剩下的代码。下面通过一小段代码来解释go的使用://首先,我们先实现一个Add()函数funcAdd(a,bint){c:=a+bfmt.Println(c)}goAdd(1,2)//使用go关键字让函数并发执行Go的并发执行就是这么简单。当你在函数前添加go关键字时,该函数将在一个新的goroutine中并发执行。当该函数执行完毕后,新的goroutine这个goroutine就完成了。但是需要注意的是,如果函数有返回值,返回值会被丢弃。所以什么时候使用go需要相应的考虑。那我们就用一个案例来体验下Go的并发是什么样子的。新建一个源文件goroutine2.go,输入如下代码:packagemainimport"fmt"funcAdd(a,bint){c:=a+bfmt.Println(c)}funcmain(){fori:=0;i<10;i++{goAdd(i,i)}}执行goroutine.go文件会发现屏幕上什么都没有,但是程序不会报错。是什么原因?原来当主程序执行到for循环时,启动了10个goroutine,然后主程序刚退出,这10个启动的goroutine还没来得及执行Add()函数,所以程序不会有任何输出。也就是说,主goroutine不等待其他goroutine执行完毕。Go语言提供的通道是为了解决并发通信的问题而设计的,我们将在下一节详细介绍。总结学习go语言,就必须学习并发。通过这一节,我们知道协程非常容易创建,而且非常轻量级,只占用4k。其他语言都好用。MB协程的使用还需要配合数据传输。Producers消费者模型,后面会讲到协程的调度。另外,并发BUG的定位和解决是一个老生常谈的问题,平时要注意良好的代码风格和编程习惯。本文转载自微信公众号“机智的程序员熊”,可通过以下二维码关注。转载本文请联系机智的程序员小熊公众号。
