• 6.1 go协程
    • 链接

    6.1 go协程

    go协程类似一个线程,但是go协程是由go自己调度,而不是系统。在协程中的代码可以和其他代码并发执行。让我们看一个例子:

    1. package main
    2. import (
    3. "fmt"
    4. "time"
    5. )
    6. func main() {
    7. fmt.Println("start")
    8. go process()
    9. time.Sleep(time.Millisecond * 10) // this is bad, don't do this!
    10. fmt.Println("done")
    11. }
    12. func process() {
    13. fmt.Println("processing")
    14. }

    这个例子有一些有趣的事,但是最重要的是了解我们是如何启动一个go协程。我们只是简单的将go关键字附在我们想要执行的函数前面即可。如果我们只想执行一小段代码,例如上面的例子一样,我们可以使用一个匿名函数。需要注意的是,匿名函数不只是在go协程中使用,其他地方也可以。

    1. go func() {
    2. fmt.Println("processing")
    3. }()

    go协程很容易创建且开销较小。最终多个go协程将会在同一个底层的系统线程上运行。这也常称之为M:N线程模型,因为我们有M个应用线程(go协程)运行在N个系统线程上。结果就是,一个go协程的开销和系统线程比起来相对很低(一般都是几KB)。在现代的硬件上,有可能拥有成千上万个go协程。

    另外,这里还隐藏了映射和调度的复杂性。我们只需要说这段代码需要并发执行,然后让go自己去处理。

    如果我们回到刚刚的例子中,你将会注意到我们使用了Sleep让程序等待了几毫秒。这是因为主进程在退出前协程才有机会去执行(主进程在退出前不会等待所有协程都执行完毕)。为了解决这个问题,我们必须让代码协同。

    链接

    • 目录
    • 上一节:并发
    • 下一节:同步