文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

你是否真的了解 Go 语言中的并发处理?

2023-10-20 01:15

关注

Go 语言作为一门新兴的编程语言,在并发处理方面有着独特的优势。然而,很多人对于 Go 语言中的并发处理还存在着一些疑惑。本文将为大家详细介绍 Go 语言中的并发处理,并通过演示代码让大家更好地理解。

一、什么是并发处理

在计算机科学中,进程是指正在执行的程序实例,而线程是进程内部的一个实体,用于执行指令序列。在单核处理器时代,我们只能通过时间片轮转的方式来实现多任务处理,也就是说,每个进程或者线程轮流占用 CPU 时间片,以达到并发执行的效果。但是在多核处理器时代,我们可以通过将不同的线程分配到不同的 CPU 核心上来实现真正的并行处理,从而大大提高程序的执行效率。

而并发处理则是在单核或者多核处理器上,通过合理地分配 CPU 时间片,让多个线程同时进行,以达到提高程序执行效率的目的。在 Go 语言中,通过 goroutine 的方式可以轻松实现并发处理。

二、Go 语言中的 goroutine

在 Go 语言中,我们可以通过关键字 go 来启动一个 goroutine。一个 goroutine 可以理解为一个轻量级的线程,它的创建成本非常低,因此可以在程序中启动大量的 goroutine,以实现高效的并发处理。

下面是一个简单的例子,用于演示如何启动一个 goroutine:

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello world!")
}

func main() {
    go sayHello()
    time.Sleep(1 * time.Second)
}

在这个例子中,我们定义了一个 sayHello 函数,用于输出 "Hello world!"。然后,在 main 函数中,我们通过 go sayHello() 的方式启动了一个 goroutine。最后,通过 time.Sleep(1 * time.Second) 的方式让主线程等待 1 秒钟,以确保 goroutine 有足够的时间输出 "Hello world!"。

三、Go 语言中的并发模型

在 Go 语言中,我们可以通过 channel 来实现不同 goroutine 之间的通信。channel 可以理解为一条管道,用于在不同的 goroutine 之间传递数据。一个 goroutine 可以向 channel 中发送数据,而另一个 goroutine 则可以从 channel 中接收数据。

下面是一个简单的例子,用于演示如何使用 channel 实现不同 goroutine 之间的通信:

package main

import (
    "fmt"
    "time"
)

func producer(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
        time.Sleep(100 * time.Millisecond)
    }
    close(ch)
}

func consumer(ch <-chan int) {
    for i := range ch {
        fmt.Println(i)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

在这个例子中,我们定义了一个 producer 函数和一个 consumer 函数,用于分别向 channel 中发送数据和从 channel 中接收数据。在 main 函数中,我们通过 make(chan int) 创建了一个 channel,然后通过 go producer(ch) 的方式启动了一个 goroutine 来向 channel 中发送数据。最后,我们通过 consumer(ch) 的方式从 channel 中接收数据,并将其输出到控制台上。

需要注意的是,当一个 goroutine 向一个已经关闭的 channel 中发送数据时,程序会出现 panic。因此,在 producer 函数中,我们通过 close(ch) 的方式关闭了 channel。

四、Go 语言中的并发控制

在进行并发处理时,我们通常需要对不同的 goroutine 进行控制,以确保它们的执行顺序和执行结果符合我们的预期。在 Go 语言中,我们可以通过 sync 包中的互斥锁和条件变量来实现并发控制。

下面是一个简单的例子,用于演示如何使用互斥锁和条件变量实现并发控制:

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup
var mu sync.Mutex
var cond = sync.NewCond(&mu)
var counter int

func producer() {
    for i := 0; i < 10; i++ {
        mu.Lock()
        counter++
        fmt.Println("producer:", counter)
        cond.Signal()
        mu.Unlock()
        time.Sleep(100 * time.Millisecond)
    }
    wg.Done()
}

func consumer() {
    for i := 0; i < 10; i++ {
        mu.Lock()
        for counter == 0 {
            cond.Wait()
        }
        counter--
        fmt.Println("consumer:", counter)
        mu.Unlock()
        time.Sleep(100 * time.Millisecond)
    }
    wg.Done()
}

func main() {
    wg.Add(2)
    go producer()
    go consumer()
    wg.Wait()
}

在这个例子中,我们定义了一个 producer 函数和一个 consumer 函数,用于分别向共享变量 counter 中增加数据和从 counter 中减少数据。在 main 函数中,我们通过 wg.Add(2) 的方式告诉程序需要等待两个 goroutine 执行完毕,然后通过 go producer() 和 go consumer() 的方式启动了这两个 goroutine。最后,通过 wg.Wait() 的方式等待两个 goroutine 执行完毕。

需要注意的是,在使用条件变量时,我们需要先获取互斥锁,然后才能调用 Wait 或者 Signal 函数。在 Wait 函数被调用时,当前的 goroutine 会被阻塞,直到另外一个 goroutine 调用了 Signal 函数,唤醒当前的 goroutine。

总结

通过本文的介绍,相信大家已经对 Go 语言中的并发处理有了更深入的了解。在实际开发中,合理地利用 goroutine、channel、互斥锁和条件变量等技术,可以帮助我们轻松实现高效的并发处理,提高程序的执行效率。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯