What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back.
你所浪费的今天是昨天死去的人奢望的明天; 你所厌恶的现在是未来的你回不去的曾经。
什么是goroutine
goroutines是与其他函数或方法同时运行的函数或方法。
goroutines可以被认为是轻量级的线程。与线程相比,创建goroutine的成本很小。因此它的应用程序通常有数千个并发运行的goroutines。
goroutines优于线程的优势
与线程相比,goroutine开销很小。它们的堆栈大小只有几kb,并且堆栈可根据应用程序的需要增长和缩小,而线程,堆栈大小必须指定并固定。
goroutine被多路复用到更少数量的os线程。在一个有数千个例程的程序中可能只有一个线程。如果该线程中的任何goroutine阻止了并等待用户输入,则会创建另一个os线程,并将其余的goroutine移至新的os线程。所有这些都受到运行时的影响,我们作为程序员从这些复杂的细节中抽象出来,并得到一个干净的api来处理并发。
goroutines使用channel进行通信。channel的设计可防止使用goroutine访问共享内存时发生资源竞争。channel可以被认为是一个与某个goroutine通信的管道。
如何开启一个groutine
使用关键字go前缀函数或方法调用,因此将会产生一个并发运行的新goroutine。
实例解析:
package main
import (
"fmt"
)
func hello() {
fmt.Println("Hello world goroutine")
}
func main() {
go hello()
fmt.Println("main function")
}
输出: main function
注意: 此时的go hello()会开启一个新的协程,并与main的主线程并行运行。但是程序在调用go hello()后会立即返回,继续往下main的执行,忽略goroutine的输出,那么main程并不会等待新协程的结束而直接退出.
如果主程序终止,那么程序将被终止,并且其他所有goroutine将会终止执行。
启动多个goroutine
让我们编写一个启动多个goroutine的程序,以更好地理解goroutine。
ackage main
import (
"fmt"
"time"
)
func numbers() {
for i := 1; i <= 5; i++ {
time.Sleep(250 * time.Millisecond)
fmt.Printf("%d ", i)
}
}
func alphabets() {
for i := 'a'; i <= 'e'; i++ {
time.Sleep(400 * time.Millisecond)
fmt.Printf("%c ", i)
}
}
func main() {
go numbers()
go alphabets()
time.Sleep(3000 * time.Millisecond)
fmt.Println("main terminated")
}
疑惑:
你可能会疑惑, 如果第一个goroutine创建之后, 其中的有sleep那么导致第二个goroutine的堵塞或者等待创建中, 当第一个goroutine输出完成,再来执行第二个goroutine的创建和执行。
解答:
上面我们说过, 主进程main在执行到go FUNC()时, 执行简单的调用后立刻返回,并不关心新goroutine中的Code所执行的任何输出。所以main会顺序执行code语句。
最上面的两个goroutine是并行执行的。
这就是关于channel简单的介绍。
有疑问加站长微信联系(非本文作者)