• goroutine的一个常见问题


    转自:http://blog.dccmx.com/2012/03/small-problem-about-goroutine/

    goroutine是Go语言的标志性特性之一。配合channel,形成了Go语言处理并发的基础。但是,目前还有些小问题,或者说小不爽。就是会给你造成真并行的假象。

    看下面的例子:

    package main
     
    import (
      "time"
      "runtime"
    )
     
    func main () {
      ch := make(chan int)
     
      go func(ch chan int) {
        time.Sleep(1 * 1e9)
        ch <- 1
      }(ch)
     
      go func(ch chan int) {
        for {
          select {
          case <-ch:
            println("got!!!")
            return
          default:
            println("waiting...")
          }
        }
      }(ch)
     
      time.Sleep(2 * 1e9)
    }

    这里,我们的意图很明显,用一个goroutine做定时器,时间到了向channel发一信号,再用一个goroutine做事,收到信号后停止,最后一行sleep是为了防止main函数退出导致其他goroutine退出(为了省代码,这里不用channel同步了)。看起来天衣无缝,很是完美,惊叹一下Go的简洁优美。但是,运行之后会发现,一直输出waiting…,永远不会退出!

    为什么??

    因为Go语言现在的实现还不是很成熟,默认情况下,同时只有1个goroutine在跑,而当这个goroutine阻塞的时候,才会调度到其他的goroutine去,就像协程,不过这里由Go语言运行时帮你调度。

    这个例子有三个解决方法。

    1.在main函数里面第一行调用runtime.GOMAXPROCS(2)函数,将同时goroutine数设为2(或者更大),这个解决方法至少在我的双核机上跑是没问题的。1秒后就输出got!!!然后结束了。

    2.制造阻塞,比如在println(“waiting…”)后面调用time.Sleep(1 * 1e8),这样输出10个waiting…后就got了。

    3.手动切换,在println(“waiting…”)后面调用runtime.Gosched(),手动切换goroutine,这样也能结束。

    这个问题很典型,初学者经常会中招,虽然从语义上讲,原始的做法并没有错,但是由于Go运行时还不够成熟(至少Go1看来是不打算解决了,以后会取消GOMAXPROCS改为自动判断),总之,大家小心点就好。

  • 相关阅读:
    iframe局部刷新的二种实现方法
    iframe之局部刷新
    iframe之局部刷新
    JavaScript设计模式之一Interface接口
    UNIX环境高级编程——线程与进程区别
    UNIX环境高级编程——死锁
    UNIX环境高级编程——线程同步之条件变量以及属性
    UNIX环境高级编程——线程同步之读写锁以及属性
    UNIX环境高级编程——线程同步之互斥量
    UNIX环境高级编程——pthread_create的问题
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/3040312.html
Copyright © 2020-2023  润新知