美文网首页
Golang并发

Golang并发

作者: TZX_0710 | 来源:发表于2019-12-05 11:29 被阅读0次

    在编写 Socket 网络程序时,需要提前准备一个线程池为每一个 Socket 的收发包分配一个线程。开发人员需要在线程数量和 CPU 数量间建立一个对应关系,以保证每个任务能及时地被分配到 CPU 上进行处理,同时避免多个任务频繁地在线程间切换执行而损失效率。
    虽然,线程池为逻辑编写者提供了线程分配的抽象机制。但是,如果面对随时随地可能发生的并发和线程处理需求,线程池就不是非常直观和方便了。能否有一种机制:使用者分配足够多的任务,系统能自动帮助使用者把任务分配到 CPU 上,让这些任务尽量并发运作。这种机制在 Go语言中被称为 goroutine
    goroutine 是 Go语言中的轻量级线程实现,由 Go 运行时(runtime)管理。Go 程序会智能地将 goroutine 中的任务合理地分配给每个 CPU。

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //默认启动main函数都会创建一个对应的goroutine
    func main() {
        //使用 goroutine创建匿名函数
        go func() {
            var times int
            for {
                times++
                fmt.Println("tick", times)
                time.Sleep(time.Second)
            }
        }()
        // 接受命令行输入, 不做任何事情
        //如果不采用 这种方式也可以采用其他方式
        //因为 golang会默认为main创建一个goroutine  当遇到 go func的时候会重新开启一个goroutine  main函数的goroutine
        //继续执行下去
        var input string
        fmt.Scanln(&input)
    }
    

    Go语言中如果两个或者多个 goroutine 在没有互相同步的情况下,访问某个共享的资源,并试图同时读和写这个资源,就处于相互竞争的状态,这种情况被称作竞争状态(race candition)。
    竞争状态的存在是让并发程序变得复杂的地方,十分容易引起潜在问题。对一个共享资源的读和写操作必须是原子化的,换句话说,同一时刻只能有一个 goroutine 对共享资源进行读和写操作。

    package main
    
    import (
        "fmt"
        "runtime"
        "sync"
    )
    
    var (
        // counter 是所有goroutine 都要增加其值的变量
        counter int
        // wg 用来等待程序结束
        wg sync.WaitGroup
    )
    // main 是所有Go 程序的入口
    func main() {
        // 计数加 2,表示要等待两个goroutine
        wg.Add(2)
        // 创建两个goroutine
        go incCounter()
        go incCounter()
        // 等待 goroutine 结束
        wg.Wait()
        fmt.Println("Final Counter:", counter)
    }
    // incCounter 增加包里counter 变量的值
    func incCounter() {
        // 在函数退出时调用Done 来通知main 函数工作已经完成
        defer wg.Done()
        for count := 0; count < 2; count++ {
            // 捕获 counter 的值
            value := counter
            // 当前 goroutine 从线程退出,并放回到队列
            runtime.Gosched()
            // 增加本地value 变量的值
            value++
            // 将该值保存回counter
            counter = value
        }
    }
    最后输出结果值为2 多次运行的结果也可能会出现 3 4
    原因是每个goroutine 线程都会覆盖前一个goroutine所做的操作,也就是说counter每次只能由一个线程操作
    传统开发者模式需要维护线程池与CPU的关系 ,Golang当中也提供支持。
    采用 如下设置多核运行  runtime.NumCPU获取 当前的CPU数量
    runtime.GOMAXPROCS(runtime.NumCPU())
    

    相关文章

      网友评论

          本文标题:Golang并发

          本文链接:https://www.haomeiwen.com/subject/fildgctx.html