zoukankan      html  css  js  c++  java
  • Golang并发编程优势与核心goroutine及注意细节

    Go语言为并发编程而内置的上层API基于CSP(communication sequential processes,顺序通信进程)模型。这就意味着显式锁都是可以避免的,比如资源竞争,比如多个进程同时获取文件资源需要修改,首先拿到资源的进程加上锁,等修改完之后把锁去掉,然后再给下一个进程来进行修改,只有这样才不会出现数据不一致。但是go语言不是通过锁的方式,是通过通信的方式,安全的通道发送和接收数据以实现同步,这就大大的简化了并发编程的编写。

    一般情况下,一个普通的计算机跑十几二十几个线程就有点负载过大,但是同样这台机器却可以让成千甚至过万哥goroutine进行资源竞争

    goroutine是什么?
    goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需要极少的栈内存(大概是4-5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。

    创建goroutine

    创建goroutine只需在函数调用语句前添加go关键字,就可以创建并发执行单元。开发人员无需了解任何执行细节,调度器会自动将其安排到合适的系统线程上执行。

    在并发编程里,我们通常想将一个过程切分成几块,然后让每个goroutine各自负责一块工作。当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine,新的goroutine会用go语句来创建,至于主和子谁先执行,由系统决定。重点:主协程退出了,其它子协程也要跟着退出;其次,主协程先退出导致子协程没来得及调用

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func newTask() {
        for {
            fmt.Println("this is a newTask")
            time.Sleep(time.Second) //延时1s
        }
    }
    
    func main() { //可以理解为主 goroutine
    
        go newTask() //新建一个协程, 新建一个任务
    
        for {
            fmt.Println("this is a main goroutine")
            time.Sleep(time.Second) //延时1s
        }
        //newTask()  子协程(goroutine)如果放在这会执行不到,因为程序都是单业务。for循环是一个任务,下面执行不到
    
        //go newTask() 但是前面加上go关键字,放到下面也没法执行
    }
    this is a main goroutine
    this is a newTask
    this is a main goroutine
    this is a newTask
    this is a main goroutine
    this is a newTask
    this is a main goroutine
    this is a newTask

    主协程退出了,其它子协程也要跟着退出。

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //主协程退出了,其它子协程也要跟着退出
    func main() {
    
        go func() {
            i := 0
            for {
                i++
                fmt.Println("子协程 i = ", i)
                time.Sleep(time.Second)
            }
    
        }()
    
        i := 0
        for {
            i++
            fmt.Println("main i = ", i)
            time.Sleep(time.Second)
    
            if i == 2 {
                break
            }
        }
    
    }
    main i =  1
    子协程 i =  1
    main i =  2
    子协程 i =  2

    主协程先退出导致子协程没来得及调用

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //主协程退出了,其它子协程也要跟着退出
    func main() {
    
        go func() {
            i := 0
            for {
                i++
                fmt.Println("子协程 i = ", i)
                time.Sleep(time.Second)
            }
    
        }()
    
    }
    //执行代码并无任何输出,因为主协程先执行完退出
  • 相关阅读:
    需求获取过程中的逆向沟通
    程序员==生 涯 篇
    算法设计
    灯的启示:微软对唐骏的面试题
    使用Gzip压缩提升WEB服务器性能
    简历误区
    招聘编辑的七道面试题
    web2.0及其相关技术
    经典面试题助你成功就业
    逗号网站推广营销策略
  • 原文地址:https://www.cnblogs.com/wt645631686/p/9656047.html
Copyright © 2011-2022 走看看