• go channel


    channel是golang用来线程间通信而设计的,可以理解为异步IO。常用的应用场景:等待mysql的返回值,等待curl请求的返回值,等待定时器返回等。

    本来想展示channel遇到的各种错误,但是有些错误不重要,如果写出来会让整篇文章先得不那么顺畅,所以只写重要的点,忽略不重要的点。

    channel的写入读取

    初步理解:channel可以理解为buffer,支持写入操作和读取操作。

    package main
    
    import (
        "fmt"
    )
    
    var _ = fmt.Sprintf("")
    
    var ch chan int = make(chan int, 1)
    
    func main() {
       //写入channel
        ch <- 1
        //读取channel
        mych := <-ch                                                                                                                      
        fmt.Println(mych)
    
        var stop string
        fmt.Scanln(&stop)
        fmt.Println(stop)
    }

    输出:

    1
    abc
    abc

    注意:channel的写入和读取最好是成对使用,如果不成对出现的话,读者可能需要自己实践和考虑下。

    channel返回超时

    golang提供的select可以用来处理channel返回超时。

    select机制支持多个channel的等待,如果有一个返回则继续执行,也支持default(对default没有遇到合适的例子所以不做更多介绍)。

    想象一种场景,主线程在等待某个channel返回,但是该channel执行时间过长,主线程判断该channel超时我不再等待这次返回,程序要继续执行。看下面的例子

    package main                                                                                                                          
    
    import (
        "fmt"
        "runtime"
        "time"
    )
    
    var _ = fmt.Sprintf("")
    
    var ch chan int = make(chan int, 1)
    
    func main() {
        runtime.GOMAXPROCS(runtime.NumCPU())
    
        go writeCh()
        readCh()
    
        var stop string
        fmt.Scanln(&stop)
        fmt.Println(stop)
    }
    
    func readCh() {
        select {
        case ch1 := <-ch:
            fmt.Println(ch1)
            return
        //设置1秒超时
        case <-time.After(time.Second):
            fmt.Println("read timeout")
        }
    }
    
    func writeCh() {
        //等待2秒后写入,使超时生效
        time.Sleep(time.Second * 2)
        ch <- 1
    }
    
    /*
    输出:
    read timeout
    abc
    abc
    */

    读取进程依据两个channel的返回次序执行,先返回先执行。可以看到timeout先返回。(可以试试把writeCh的Sleep去掉)

    需要注意的是,channel的读写调用顺序最好和上面例子保持一致,先go程调用写入进程,主线程中执行读取操作。两者的顺序不能反(可以试试顺序搞反的执行结果)

    channel的关闭

    用完channel不再继续使用,可以关闭此channel。用close()函数来实现。那如何判断channel是否已关闭?可以用ch的返回值来判断,第二个返回值,false是已关闭,true是未关闭。特别的,如果channel关闭之前已写入数据,那么执行Close()后的第一个读取操作会返回,内容和true。

    package main                                                                                                                          
    
    import (
        "fmt"
        "runtime"
        "time"
    )
    
    var _ = fmt.Sprintf("")
    
    var ch chan int = make(chan int, 1)
    
    func main() {
        runtime.GOMAXPROCS(runtime.NumCPU())
    
        go writeCh()
        readCh()
    
        var stop string
        fmt.Scanln(&stop)
        fmt.Println(stop)
    
        close(ch)
                   
        var more bool
        var chi int
        //第一个返回channel的值,第二个返回是否还有更多的数据
        chi, more = <-ch
        fmt.Println(chi, more)
                     
        //关闭后再往channel中写入会报错
        //ch <- 1    
    }                
                     
    func readCh() {
        select { 
        case ch1 := <-ch:
            fmt.Println(ch1)
        case <-time.After(time.Second):
            fmt.Println("read timeout")
        }
    }
    
    func writeCh() {
        //time.Sleep(time.Second * 2)
        ch <- 1
    }
    
    /*
    输出:
    1
    abc
    abc
    0 false
    */
  • 相关阅读:
    CRM PrincipalObjectAccess(POA)
    crmForm.SubmitCRMForm
    transactionCurrencyId needs to be supplied to format a transaction money field.
    GitLab 之 Linux十分钟快装
    GitLab 之 Linux十分钟快装
    秒杀系统架构分析与实战
    秒杀系统架构分析与实战
    秒杀系统架构分析与实战
    创建微服务?请先回答这10个问题
    创建微服务?请先回答这10个问题
  • 原文地址:https://www.cnblogs.com/helww/p/4885712.html
Copyright © 2020-2023  润新知