设为首页 加入收藏

TOP

goroutine(一)
2019-02-21 12:08:07 】 浏览:48
Tags:goroutine

前段时间学习 go, 专门整理的关于 goroutine 的理解.

What's goroutine? It's an independently executing function launched by a go statement.
It has its own call stack, which grows and shrinks as required.
It's very cheap. It's practical to have thousands, even hundreds of thousands of goroutines.
It's not a thread.
There might be only one thread in a program with thousands of goroutines.
Instead, goroutines are multiplexed dynamically onto threads as needed to keep all the goroutines running.
But if you think of it as very cheap thread, you won't be far off.

1. 理解"并发" 不是 "并行"

并发: 同时处理一些事
并行: 同时做一些事
concurrency is the composition of independently executing computations.
concurrency is not parallelism, although it enables parallelism.
If you have only one processor, your program can still be concurrent, but it can't be parallel.
On the other hand, a well-written program might run efficiently in parallel on a multiprocessor. That property could be important...
---Rob Pike

举例: 比如你是一个公司的CEO, 你每天上午会抽出两个小时的时间统一处理回复邮件, 接待下属的各种问题. 那么当你正在回邮件的时候, 有人敲门进来找你签字, 那么你就停下手里的邮件, 把字签了, 然后再继续回来写邮件. 那么在这两个小时里, 你回了好几封邮件, 还签了好几份文件. 而这个过程就可以称为并发. 因为你并没有一边回邮件, 一边签文件, 所以这不是并行. 

2. goroutine 的用法

在需要做并发处理的方法名前面加个 go 关键字即可
首先看下没有引入 goroutine 时的情况

package main import ( "fmt" "time" ) func say(s string) { for i := 0; i<3; i++ { fmt.Println(s) time.Sleep(time.Millisecond*100) } } func main() { say("Hey") say("There") } 

以下为输出, 这里呢, 就是一个顺序执行, 先执行第一个 say 方法, 循环3次输出, 然后执行第二个say方法, 循环3次输出. 但是这不符合我们的预期, 我希望输出的是交替输出. 也就是输出一个 Hey, 输出一个 There ....... 这个需求就有点像我们前面提到的例子, 两个事物需要交替处理

Hey
Hey
Hey
There
There
There 

这样就引出 goroutine 来解决这个并发的问题, 但是具体怎么用, 先看几个代码片段来了解一下:
(1)

func main() { say("Hey") go say("There") } 

输出, 执行过程: 执行第一个 say() 方法, 连续输出三个 "Hey" ---> 执行第二个 say()方法, 而这里由于 goroutine 会立即返回 ---> 程序接着执行后面的代码, 所以第二个方法还没有执行完毕 ---> 程序退出.

Hey
Hey
Hey

(2)

func main() { go say("Hey") say("There") } 

输出, 执行过程: 执行第一个 say() 方法, 根据 goroutine 立即返回的特性 ---> 执行第二个 say()方法, 输出第一个 There ---> 大家别忘了在 say 方法中, 还有这样一行代码

time.Sleep(time.Millisecond*100) 

它的作用就是模拟缓慢的函数调用, 让程序暂停指定的时间. 多亏了这个延迟, 让第二个循环输出一次之后, 就给了第一个循环的机会 ---> 输出 Hey, 之后按照上术逻辑继续循环输出. 

There
Hey
There
Hey
There
Hey

(3)

func main() { go say("Hey") go say("There") } 

输出, 执行过程: 执行第一个 goroutine, 立即返回 ---> 执行第二个 goroutine, 立即返回 ---> 程序退出, 因此没有任何输出.

Process finished with exit code 0

(4)

func main() { go say("Hey") go say("There") // 使程序延迟退出 time.Sleep(time.Second) } 

通过 time.Sleep 函数使程序延迟一秒退出, 就给了 goroutine 执行的时间, 这里, 我尝试多次刷新, 输出的顺序都不相同, 同时, 还可以尝试把 say 函数里的 time.Sleep 去掉, 再多次执行, 也会发现输出的顺序都不同.我觉得这也充分体现了goroutine 的并发执行. 
输出情况一

Hey
There
There
Hey
There
Hey

输出情况二

There
Hey
Hey
There
Hey
There

总结一下 goroutine 的特点: 通过使用 goroutine, 可以在调用函数之后立即执行后面的代码, 但是使用 goroutine 的函数依然会执行, 但不会阻塞程序中其他代码行的执行. 

3. 使用 WaitGroup 函数控制程序的退出

在上面的最后一个例子中, 我们使用了 time.Sleep 人为控制程序延迟1秒退出, 但是在实际开发中, 我们无法去精准的算出, 所有的 goroutine 完成返回需要多少时间, 所以这样认为控制程序的退出时间, 并不是一个好办法, 因此就引出了 sync 包的 WaitGroup 函数. 使用方法详见注释如下:

package main import ( "fmt" // 引入sync 包 "sync" "time" ) // 声明 WaitGroup 类型的变量 wg var wg sync.WaitGroup func say(s string) { for i := 0; i<3; i++ { fmt.Println(s) time.Sleep(time.Millisecond*100) } // 告知所有的 goroutine 运行结束, 程序可以返回了 wg.Done() } func main() { //添加一个 goroutine 到 w
编程开发网
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇[Go] golang的select多路选择功能 下一篇使用Golang搭建web服务

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

array(4) { ["type"]=> int(8) ["message"]=> string(24) "Undefined variable: jobs" ["file"]=> string(32) "/mnt/wp/cppentry/do/bencandy.php" ["line"]=> int(214) }