• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    golang coroutine 的等待与死锁用法

    直接上代码:

    1. 第一种情况

    如果没有select{}, main 主线程不会等待coroutine运行,导致coroutine得不到机会运行。

    You are requesting eventual scheduling (using the two go statements)

    of two goroutines and then you exit main without giving the scheduler

    a chance to do anything.

    有了select, 程序正常运行。

    package main
    import (
     "fmt"
            "time"
    )
    func main() {
     go func1()
     go func2()
     select{}
    }
    func func1() {
           for{
         fmt.Println("here1")
                time.Sleep(10 * time.Minute)
            }
    }
    func func2() {
           for{
        fmt.Println("here2")
               time.Sleep(10 * time.Minute)
           }
    }
    

    2. coroutine有机会运行

    但是会发生死锁, fatal error: all goroutines are asleep - deadlock!

    The goroutine executing func1 exited, ditto for func2. The main goroutine is blocked with no hope to recover while no other goroutine can be scheduled.

    package main
    import (
     "fmt"
     //"time"
    )
    func main() {
     go func1()
     go func2()
     select {
     }
    }
    func func1() {
     fmt.Println("here1")
    }
    func func2() {
     fmt.Println("here2")
    }
    

    3. 第三种情况, 正常运行

    package main
    import (
     "fmt"
    )
    var c = make(chan int, 2)
    func main() {
     go func1()
     go func2()
     -c
     -c
     fmt.Println("ok")
    }
    func func1() {
     fmt.Println("here1")
     c - 1
    }
    func func2() {
     fmt.Println("here2")
     c - 1
    }
    

    4. 实现上面的目的的另外一种方法:

      var wg sync.WaitGroup
        var urls = []string{
                "http://www.golang.org/",
                "http://www.google.com/",
                "http://www.somestupidname.com/",
        }
        for _, url := range urls {
                // Increment the WaitGroup counter.
                wg.Add(1)
                // Launch a goroutine to fetch the URL.
                go func(url string) {
                        // Decrement the counter when the goroutine completes.
                        defer wg.Done()
                        // Fetch the URL.
                        http.Get(url)
                }(url)
        }
        // Wait for all HTTP fetches to complete.
        wg.Wait()

    补充:golang中死锁的情况分析

    Golang关于channel死锁情况的汇总以及解决方案

    直接读取空channel的死锁

    当一个channel中没有数据,而直接读取时,会发生死锁:

    func main() {
        q := make(chan int, 2)
        -q
    }

    错误提示:

    fatal error: all goroutines are asleep - deadlock!

    goroutine 1 [chan receive]:

    main.main()

    /home/erick/Desktop/Book/Parallel/final.go:159 +0x4d

    exit status 2

    上述代码中,创建了一个2个容量的channel,直接读取发生了死锁情况。

    修正方案,使用select方法阻止,在default中放置默认处理方式:

    func main() {
        q := make(chan int, 2)
        select {
        case v := -q:
            fmt.Println(v)
        default:
            fmt.Println("nothing in channel")
        }
    }

    输出:

    nothing in channel

    过度写入数据造成的死锁

    写入数据超过channel的容量,也会造成死锁:

    func main() {
        q := make(chan int, 2)
        q - 1
        q - 2
        q - 3
    }

    解决方案,与写入的方式一样,使用select方法阻止,在default中放置默认处理方式:

    func main() {
        q := make(chan int, 2)
        q - 1
        q - 2
        select {
        case q - 3:
            fmt.Println("ok")
        default:
            fmt.Println("wrong")
        }
    }
    

    向已经关闭的channel中写入数据

    这种造成的不是死锁,而是产生panic。

    func main() {
        q := make(chan int, 2)
        close(q)
        q - 1
    }

    代码错误:

    panic: send on closed channel

    goroutine 1 [running]:

    main.main()

    /home/erick/Desktop/Book/Parallel/final.go:154 +0x63

    exit status 2

    解决方案:只有别向已经关闭的channel写数据。。。。

    但是,可以从已经关闭的channel中读取数据:

    func main() {
        q := make(chan int, 3)
        q - 1
        q - 2
        q - 3
        close(q)
        for v := range q {
            fmt.Println(v)
        }

    下面开始讲解goroutine的读写

    package main
    import "fmt"
    func main() {
     c:=make(chan string)
     go func() {
      c-"hello"
     }()
     fmt.Println(-c)
    }

    上面这个是对的

    package main
    import "fmt"
    func main() {
     c:=make(chan string)
     fmt.Println(-c)
     go func() {
      c-"hello"
     }()
    }
    

    上面这个是错的,会发生死锁,因为程序会阻塞在fmt.Println(-c),并不会向下执行。在该行发生了阻塞,以致于下面的代码没有机会执行。因此可以总结写在读前,写操作完成后才有读操作。

    总结:

    上述提到的死锁,是指在程序的主线程中发生的情况,如果上述的情况发生在非主线程中,读取或者写入的情况是发生堵塞的,而不是死锁。

    实际上,阻塞情况省去了我们加锁的步骤,反而是更加有利于代码编写,要合理的利用阻塞。。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

    您可能感兴趣的文章:
    • 详解Golang并发操作中常见的死锁情形
    • Go 语言中的死锁问题解决
    • Go语言死锁与goroutine泄露问题的解决
    • go select编译期的优化处理逻辑使用场景分析
    • Django实现jquery select2带搜索的下拉框
    • Go语言使用select{}阻塞main函数介绍
    • matplotlib之多边形选区(PolygonSelector)的使用
    • golang中的select关键字用法总结
    • Go select 死锁的一个细节
    上一篇:go语言通过反射创建结构体、赋值、并调用对应的操作
    下一篇:golang中json和struct的使用说明
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    golang coroutine 的等待与死锁用法 golang,coroutine,的,等待,与,