广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang中的并发性是什么
  • 243
分享到

Golang中的并发性是什么

2023-07-05 12:07:23 243人浏览 安东尼
摘要

这篇文章主要介绍了golang中的并发性是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang中的并发性是什么文章都会有所收获,下面我们一起来看看吧。什么是并发性,为什么它很重要并发是指在同一时间运行

这篇文章主要介绍了golang中的并发性是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang中的并发性是什么文章都会有所收获,下面我们一起来看看吧。

    什么是并发性,为什么它很重要

    并发是指在同一时间运行多个事物的能力。你的电脑有一个CPU。一个CPU有几个线程。每个线程通常一次运行一个程序。当我们通常写代码时,这些代码是按顺序运行的,也就是说,每项工作都是背对背运行的。在并发代码中,这些工作是由线程同时运行的。

    一个很好的比喻是对一个家庭厨师的比喻。我还记得我第一次尝试煮意大利面的时候。我按照菜谱一步步地做。我切了蔬菜,做了酱汁,然后煮了意大利面条,再把两者混合起来。在这里,每一步都是按顺序进行的,所以下一项工作必须等到当前工作完成后才能进行。

    快进到现在,我在烹饪意大利面条方面变得更有经验。我现在先开始做意大利面,然后在这期间进行酱汁的制作。烹饪时间几乎减少到一半,因为烹饪意大利面条和酱汁是同时进行的。

    并发性与平行性

    并发性与并行性有些不同。并行性与并发性类似,即同时发生多项工作。然而,在并行性中,多个线程分别在进行不同的工作,而在并发性中,一个线程在不同的工作之间游走。

    因此,并发性和并行性是两个不同的概念。一个程序既可以并发地运行,也可以并行地运行。你的代码可以按顺序写,也可以按并发写。该代码可以在单核机器或多核机器上运行。把并发性看作是你的代码的一个特征,而把并行性看作是执行的一个特征。

    Goroutines, the worker Mortys

    Go使编写并发代码变得非常简单。每个并发的工作都由一个goroutine来表示。你可以通过在函数调用前使用go关键字来启动一个goroutine。看过《瑞克和莫蒂》吗?想象一下,你的主函数是一个Rick,他把任务委托给goroutine Mortys。

    让我们从一个连续的代码开始。

    package mainimport (    "fmt"    "time")func main() {    simple()}func simple() {    fmt.Println(time.Now(), "0")    time.Sleep(time.Second)    fmt.Println(time.Now(), "1")    time.Sleep(time.Second)    fmt.Println(time.Now(), "2")    time.Sleep(time.Second)    fmt.Println("done")}

    2022-08-14 16:22:46.782569233 +0900 KST m=+0.000033220 0
    2022-08-14 16:22:47.782728963 +0900 KST m=+1.000193014 1
    2022-08-14 16:22:48.782996361 +0900 KST m=+2.000460404 2
    done

    上面的代码打印出当前时间和一个字符串。每条打印语句的运行时间为一秒。总的来说,这段代码大约需要三秒钟的时间来完成。

    现在让我们把它与一个并发的代码进行比较。

    func main() {    simpleConc()}func simpleConc() {    for i := 0; i < 3; i++ {        go func(index int) {            fmt.Println(time.Now(), index)        }(i)    }    time.Sleep(time.Second)    fmt.Println("done")}

    2022-08-14 16:25:14.379416226 +0900 KST m=+0.000049175 2
    2022-08-14 16:25:14.379446063 +0900 KST m=+0.000079012 0
    2022-08-14 16:25:14.379450313 +0900 KST m=+0.000083272 1
    done

    上面的代码启动了三个goroutines,分别打印当前时间和i。这段代码花了大约一秒钟完成。这比顺序版本快了三倍左右。

    "等一下,"我听到你问。"为什么要等整整一秒?难道我们不能删除这一行以使程序尽可能快地运行吗?"好问题!让我们看看会发生什么。

    func main() {    simpleConcFail()}func simpleConcFail() {    for i := 0; i < 3; i++ {        go func(index int) {            fmt.Println(time.Now(), index)        }(i)    }    fmt.Println("done")}

    done

    嗯......。程序确实在没有任何慌乱的情况下退出了,但我们缺少来自goroutines的输出。为什么它们被跳过?

    这是因为在默认情况下,Go并不等待goroutine的完成。你知道main也是在goroutine里面运行的吗?主程序通过调用simpleConcFail来启动工作程序,但它在工作程序完成工作之前就退出了。

    让我们回到烹饪的比喻上。想象一下,你有三个厨师,他们分别负责烹饪酱料、意大利面和肉丸。现在,想象一下,如果戈登-拉姆齐命令厨师们做一盘意大利面条和肉丸子。这三位厨师将努力工作,烹制酱汁、意大利面条和肉丸。但是,在厨师们还没有完成的时候,戈登就按了铃,命令服务员上菜。很明显,食物还没有准备好,顾客只能得到一个空盘子。

    这就是为什么我们在退出节目前等待一秒钟。我们并不总是确定每项工作都会在一秒钟内完成。有一个更好的方法来等待工作的完成,但我们首先需要学习另一个概念。

    总结一下,我们学到了这些东西:

    • 工作被委托给goroutines。

    • 使用并发性可以提高你的性能。

    • 主goroutine默认不等待工作goroutine完成。

    • 我们需要一种方法来等待每个goroutine完成。

    Channels, the green portal

    goroutines之间是如何交流的?当然是通过通道。通道的作用类似于门户。你可以通过通道发送和接收数据。下面是你如何在Go中制作一个通道。

    ch := make(chan int)

    每个通道都是强类型的,并且只允许该类型的数据通过。让我们看看我们如何使用这个。

    func main() {    unbufferedCh()}func unbufferedCh() {    ch := make(chan int)    go func() {        ch <- 1    }()    res := <-ch    fmt.Println(res)}

    1

    很简单,对吗?我们做了一个名为ch的通道。我们有一个goroutine,向ch发送1,我们接收该数据并将其保存到res。

    你问,为什么我们在这里需要一个goroutine?因为不这样做会导致死

    func main() {    unbufferedChFail()}func unbufferedChFail() {    ch := make(chan int)    ch <- 1    res := <-ch    fmt.Println(res)}

    fatal error: all goroutines are asleep - deadlock!

    我们碰到了一个新词。什么是死锁?死锁就是你的程序被卡住了。为什么上面的代码会卡在死锁中?

    为了理解这一点,我们需要知道通道的一个重要特性。我们创建了一个无缓冲的通道,这意味着在某一特定时间内没有任何东西可以被存储在其中。这意味着发送方和接收方都必须同时准备好,才能在通道上传输数据。

    在失败的例子中,发送和接收的动作依次发生。我们发送1到ch,但在那个时候没有人接收数据。接收发生在稍后的一行,这意味着在接收行运行之前,1不能被发送。可悲的是,1不能先被发送,因为ch是没有缓冲的,没有空间来容纳任何数据。

    在这个工作例子中,发送和接收的动作同时发生。主函数启动了goroutine,并试图从ch中接收,此时goroutine正在向ch发送1。

    另一种从通道接收而不发生死锁的方法是先关闭通道。

    func main() {    unbufferedCh()}func unbufferedCh() {    ch3 := make(chan int)    close(ch3)    res2 := <-ch3    fmt.Println(res2)}

    0

    关闭通道意味着不能再向它发送数据。我们仍然可以从该通道中接收它。对于未缓冲的通道,从一个关闭的通道接收将返回一个通道类型的零值。

    总结一下,我们学到了这些东西:

    • 通道是goroutines之间相互交流的方式。

    • 你可以通过通道发送和接收数据。

    • 通道是强类型的。

    • 没有缓冲的通道没有空间来存储数据,所以发送和接收必须同时进行。否则,你的代码就会陷入死锁。

    • 一个封闭的通道将不接受任何数据。

    • 从一个封闭的非缓冲通道接收数据将返回一个零值。

    如果通道能保持数据一段时间,那不是很好吗?这里就是缓冲通道发挥作用的地方。

    Buffered channels, the portal that is somehow cylindrical?

    缓冲通道是带有缓冲器的通道。数据可以存储在其中,所以发送和接收不需要同时进行。

    func main() {    bufferedCh()}func bufferedCh() {    ch := make(chan int, 1)    ch <- 1    res := <-ch    fmt.Println(res)}

    1

    在这里,1被储存在ch里面,直到我们收到它。

    很明显,我们不能向一个满了缓冲区的通道发送更多的信息。你需要在缓冲区内有空间才能发送更多。

    func main() {    bufferedChFail()}func bufferedChFail() {    ch := make(chan int, 1)    ch <- 1    ch <- 2    res := <-ch    fmt.Println(res)}

    fatal error: all goroutines are asleep - deadlock!

    你也不能从一个空的缓冲通道接收。

    func main() {    bufferedChFail2()}func bufferedChFail2() {    ch := make(chan int, 1)    ch <- 1    res := <-ch    res2 := <-ch    fmt.Println(res, res2)}

    fatal error: all goroutines are asleep - deadlock!

    如果一个通道已满,发送操作将等待,直到有可用的空间。这在这段代码中得到了证明。

    func main() {    bufferedCh3()}func bufferedCh3() {    ch := make(chan int, 1)    ch <- 1    go func() {        ch <- 2    }()    res := <-ch    fmt.Println(res)}

    1

    我们接收一次是为了取出1,这样goroutine就可以发送2到通道。我们没有从ch接收两次,所以只接收1。

    我们也可以从封闭的缓冲通道接收。在这种情况下,我们可以在封闭的通道上设置范围来迭代里面的剩余项目

    func main() {    bufferedChRange()}func bufferedChRange() {    ch := make(chan int, 3)    ch <- 1    ch <- 2    ch <- 3    close(ch)    for res := range ch {        fmt.Println(res)    }    // you could also do this    // fmt.Println(<-ch)    // fmt.Println(<-ch)    // fmt.Println(<-ch)}

    1
    2
    3

    在一个开放的通道上测距将永远不会停止。这意味着在某些时候,通道将是空的,测距循环将试图从一个空的通道接收,从而导致死锁。

    总结一下:

    • 缓冲通道是有空间容纳项目的通道。

    • 发送和接收不一定要同时进行,与非缓冲通道不同。

    • 向一个满的通道发送和从一个空的通道接收将导致一个死锁。

    • 你可以在一个封闭的通道上进行迭代,以接收缓冲区内的剩余值。

    等待戈多...我的意思是,goroutines来完成,使用通道

    通道可以用来同步goroutines。还记得我告诉过你,在通过无缓冲通道传输数据之前,发送方和接收方必须都准备好了吗?这意味着接收方将等待,直到发送方准备好。我们可以说,接收是阻断的,意思是接收方将阻断其他代码的运行,直到它收到东西。让我们用这个巧妙的技巧来同步我们的goroutines。

    func main() {    basicSyncing()}func basicSyncing() {    done := make(chan struct{})    go func() {        for i := 0; i < 5; i++ {            fmt.Printf("%s worker %d start\n", fmt.Sprint(time.Now()), i)            time.Sleep(time.Duration(rand.Intn(5)) * time.Second)        }        close(done)    }()    <-done    fmt.Println("exiting...")}

    我们做了一个done通道,负责阻断代码,直到goroutine完成。done可以是任何类型,但struct{}经常被用于这些类型的通道。它的目的不是为了传输结构,所以它的类型并不重要。

    一旦工作完成,worker goroutine 将关闭 done。此时,我们可以从 done 中接收,它将是一个空结构。接收动作解除了代码的阻塞,使其可以退出。

    这就是我们使用通道等待goroutine完成的方式。

    关于“Golang中的并发性是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Golang中的并发性是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网GO频道。

    您可能感兴趣的文档:

    --结束END--

    本文标题: Golang中的并发性是什么

    本文链接: https://www.lsjlt.com/news/351714.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Golang中的并发性是什么
      这篇文章主要介绍了Golang中的并发性是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang中的并发性是什么文章都会有所收获,下面我们一起来看看吧。什么是并发性,为什么它很重要并发是指在同一时间运行...
      99+
      2023-07-05
    • golang并发控制的方法是什么
      在Go语言中,可以使用以下几种方法来控制并发:1. Goroutine:Goroutine是Go语言中的轻量级线程,可以通过go关键...
      99+
      2023-10-20
      golang
    • golang控制并发数的方法是什么
      在Golang中,可以使用goroutine和channel来控制并发数。以下是几种常见的方法: 通过控制goroutine的数...
      99+
      2023-10-27
      golang
    • golang控制并发数量的方法是什么
      在golang中,可以使用goroutine和channel来控制并发数量。以下是一些常用的方法: 使用goroutine和Wai...
      99+
      2023-10-21
      golang
    • golang中的并发和并行
      golang中默认使用一个CPU,这时程序无法并发,只能是并发。因为始终只有一个CPU在运行。 package main import ( "fmt" ...
      99+
      2022-11-12
    • golang限制最大并发数的方法是什么
      在Go语言中,可以使用`sync.WaitGroup`和`chan`来限制最大并发数。 使用`sync.WaitGroup`:`s...
      99+
      2023-10-26
      golang
    • 一文带你了解Golang中的并发性
      目录什么是并发性,为什么它很重要并发性与平行性Goroutines, the worker MortysChannels, the green portal总结并发是一个很酷的话题,...
      99+
      2023-03-15
      Golang并发性 Go 并发性
    • Golang CSP并发机制及使用模型是什么
      这篇文章主要介绍了Golang CSP并发机制及使用模型是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang CSP并发机制及使用模型是什么文章都会有所收获,下面我们一起来看看吧...
      99+
      2023-06-30
    • java中什么是并发?
      java中什么是并发?并发:是指在某个时间段内,多任务交替的执行任务。当有多个线程在操作时,把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行。 在一个时间段的线程代码运行时,其它线程处于挂起状。简单来说,就是cpu在同一时刻...
      99+
      2016-05-09
      java教程 java 并发
    • Golang并发模型中的同步与性能优化
      在Golang的并发模型中,同步和性能优化是两个关键的方面。同步指的是协调多个并发操作的执行顺序,以避免数据竞争和不一致性的问题。G...
      99+
      2023-10-08
      Golang
    • Golang中的并发同步技术与性能优化
      在Golang中,有几种常见的并发同步技术可以用于解决并发访问共享资源时的竞争条件问题,以及性能优化的问题。以下是其中一些常见的技术...
      99+
      2023-10-10
      Golang
    • JVM中Java和Scala并发性基础是什么
      本篇文章给大家分享的是有关JVM中Java和Scala并发性基础是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。处理器速度数十年来一直持续快速发展,并在世纪交替之际走到了终...
      99+
      2023-06-17
    • golang中死锁的触发事件是什么
      这篇文章主要介绍了golang中死锁的触发事件是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇golang中死锁的触发事件是什么文章都会有所收获,下面我们一起来看看吧。1、Golang中死锁的触发条件1.1...
      99+
      2023-07-05
    • golang中并发和并行的示例分析
      这篇文章主要介绍了golang中并发和并行的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是golanggolang 是Google开发的一种静态强类型、编译型、...
      99+
      2023-06-15
    • Go语言中的并发是什么
      这篇文章主要介绍“Go语言中的并发是什么”,在日常操作中,相信很多人在Go语言中的并发是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言中的并发是什么”的疑惑有所帮...
      99+
      2022-10-18
    • golang中的CSP并发模型怎么实现
      本篇内容介绍了“golang中的CSP并发模型怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 相关概念: 用户态:当一个进程在执...
      99+
      2023-06-30
    • java中并发和并行的概念是什么
      这篇文章主要介绍了java中并发和并行的概念是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Java有哪些集合类Java中的集合主要分为四类:1、List列表:有序的,可...
      99+
      2023-06-14
    • Golang并发编程之调度器初始化的方法是什么
      本篇内容主要讲解“Golang并发编程之调度器初始化的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang并发编程之调度器初始化的方法是什么”吧!1. 一些全局变量在proc.g...
      99+
      2023-07-05
    • golang开发步骤是什么
      golang开发步骤是:1、项目规划;2、环境搭建;3、编写代码;4、测试;5、构建和调试;6、优化和性能调整;7、文档编写;8、持续集成和部署;9、监控和维护。详细介绍:1、项目规划,包括明确项目的需求,功能和目标,确定项目所需的技术栈和...
      99+
      2023-12-13
      golang开发步骤 go语言 Golang
    • Golang中的并发控制和Go WaitGroup
      在Golang中,可以使用并发控制来管理多个goroutine的执行。其中,一个常见的并发控制机制是使用`sync.WaitGrou...
      99+
      2023-10-08
      Golang
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作