go并发编程(代码片段)

ryan16231112 ryan16231112     2023-04-12     505

关键词:

并发编程

Goroutine

Goroutine是Go语言特有的并发体,是一种轻量级的线程,由go关键字启动。在真实的Go语言的实现中,goroutine和系统线程也不是等价的。

一个Goroutine会以一个很小的栈启动(可能是2KB或4KB),当遇到深度递归导致当前栈空间不足时Goroutine会根据需要动态地伸缩栈的大小(主流实现中栈的最大值可达到1GB)。因为启动的代价很小,所以我们可以轻易地启动成千上万个Goroutine。

Go的运行时还包含了其自己的调度器,这个调度器使用了一些技术手段,可以在n个操作系统线程上多工调度m个Goroutine。Go调度器的工作和内核的调度是相似的,但是这个调度器只关注单独的Go程序中的Goroutine。

Goroutine采用的是半抢占式的协作调度,只有在当前Goroutine发生阻塞时才会导致调度;同时发生在用户态,调度器会根据具体函数只保存必要的寄存器,切换的代价要比系统线程低得多。运行时有一个 runtime.GOMAXPROCS 变量,用于控制当前运行正常非阻塞Goroutine的系统线程数目。

锁操作

一般情况下,原子操作都是通过“互斥”访问来保证的,通常由特殊的CPU指令提供保护。当然,如果仅仅是想模拟下粗粒度的原子操作,我们可以借助于 sync.Mutex 来实现:

import "sync"

var total struct 
    sync.Mutex
    value int


func worker(wg *sync.WaitGroup) 
    defer wg.Done()
    for i := 0; i <= 100; i++ 
        total.Lock()
        total.value += i
        total.Unlock()
    


func main() 
    var wg sync.WaitGroup
    wg.Add(2)
    go worker(&wg)
    go worker(&wg)
    wg.Wait()
    fmt.Println(total.value)

类似于java中的多线程安全类,go中也有类似的:

import (
    "sync"
    "sync/atomic"
)
var total uint64
func worker(wg *sync.WaitGroup) 
    defer wg.Done()
    var i uint64
    for i = 0; i <= 100; i++ 
        atomic.AddUint64(&total, i)
    

同步

同一个Goroutine线程内部,顺序一致性内存模型是得到保证的。但是不同的Goroutine之间,并不满足顺序一致性内存模型,需要通过明确定义的同步事件来作为同步的参考。如果两个事件不可排序,那么就说这两个事件是并发的。为了最大化并行,Go语言的编译器和处理器在不影响上述规定的前提下可能会对执行语句重新排序(CPU也会对一些指令进行乱序执行)。

func main() 
    go println("你好, 世界")

根据Go语言规范, main 函数退出时程序结束,不会等待任何后台线程。因为Goroutine的执行和 main 函数的返回事件是并发的,谁都有可能先发生,所以什么时候打印,能否打印都是未知的。

解决问题的办法就是通过同步原语来给两个事件明确排序:

func main() 
    done := make(chan int)
    
    go func()
        println("你好, 世界")
        done <- 1
    ()
    
    <-done

当 <-done 执行时,必然要求 done <- 1 也已经执行。根据同一个Gorouine依然满足顺序一致性规则,我们可以判断当 done <- 1 执行时, println("你好, 世界") 语句必然已经执行完成了。因此,现在的程序确保可以正常打印结果。

channel通信

Channel通信是在Goroutine之间进行同步的主要方法。在无缓存的Channel上的每一次发送操作都有与其对应的接收操作相配对,发送和接收操作通常发生在不同的Goroutine上(在同一个Goroutine上执行2个操作很容易导致死锁)。无缓存的Channel上的发送操作总在对应的接收操作完成前发生.

func main() 
    // 定义管道
    done := make(chan int)
    
    go func()
        println("你好, 世界")
        // 向管道发送数据
        done <- 1
    ()
    // 从管道获取数据
    <-done

go并发编程模型(代码片段)

一、前言Go语言中实现了两种并发模型,一种是依赖于共享内存实现的线程-锁并发模型,另一种则是CSP(CommunicationingSequentialProcesses,通信顺序进程)并发模型。大多数编程语言(比如C++、Java、Python... 查看详情

068-go并发编程(代码片段)

并发编程的难点在于异常处理。今天我们继续研究缩略图的并发编程,还记得之前留下的问题吗?我们的程序没有对程序返回的错误做特殊照顾。在服务器开发领域,这样的程序的显然不够健壮。1.让程序能够处理错... 查看详情

go并发编程基础-channel(代码片段)

...runtime所调度,这一点和线程不一样。也就是说,Go语言的并发是由Go自己所调度的,自己决定同时执行多少个goroutine,什么时候执行哪几个。这些对于我们开发者来说完全透明,只需要在编码的时候告诉Go语 查看详情

go语言并发编程(代码片段)

并发编程基本概念学习并发编程之前我们需要脑补几个基础知识和思考一个问题什么是串行?什么是并行?什么是并发?什么是程序?什么是进程?什么是线程?什么是协程?什么是串行?串行就是按顺序执行,就好比银行只有1个窗口,有3个... 查看详情

使用go语言实现高效的并发编程(代码片段)

文章目录概述举个例子使用并发编程来实现简单的任务处理使用同步锁来避免竞态条件使用信道来协调多个goroutine之间交互总结概述Go语言支持并发编程。你可以通过创建多个并发单元(称为goroutines)来实现多线程编程... 查看详情

使用go语言实现高效的并发编程(代码片段)

文章目录概述举个例子使用并发编程来实现简单的任务处理使用同步锁来避免竞态条件使用信道来协调多个goroutine之间交互总结概述Go语言支持并发编程。你可以通过创建多个并发单元(称为goroutines)来实现多线程编程... 查看详情

067-go并发编程(代码片段)

接下来了几篇文章,我们会重点讨论有关Go的并发编程以及常见的技术手段。当然,所有问题我们都需要从实例出发,所有的实例均来源于《TheGoProgrammingLanguage》一书的第8章。1.缩略图计算程序这个例子的目的很简单&... 查看详情

go语言并发编程(代码片段)

...万个。这也是协程也叫轻量级线程的原因。golang原生支持并发编程轻量级线程非抢占式多任务处理,由协程主动交出控制权编译器/解释器/虚拟机层面的多任务多个协程可能在一个或多个线程上运行1.1go对协程的实现goroutine--Go对... 查看详情

go语言并发编程-原子操作(代码片段)

引言举一个例子,将变量n从0开始,自增1000次,然而对于并发操作而言,当两个或两个以上的goroutines同时读取内存中的n值,然后将n+1的值放回内存,可能多次自增的结果,这个n只自增了1次!这里需要使用原子操作,以保证多... 查看详情

go语言并发编程-原子操作(代码片段)

引言举一个例子,将变量n从0开始,自增1000次,然而对于并发操作而言,当两个或两个以上的goroutines同时读取内存中的n值,然后将n+1的值放回内存,可能多次自增的结果,这个n只自增了1次!这里需要使用原子操作,以保证多... 查看详情

09.go语言并发(代码片段)

Go语言并发并发指在同一时间内可以执行多个任务。并发编程含义比较广泛,包含多线程编程、多进程编程及分布式程序等。本章讲解的并发含义属于多线程编程。Go语言通过编译器运行时(runtime),从语言上支持了并发的特性... 查看详情

云原生时代崛起的编程语言go并发编程实战(代码片段)

Go语言是天然并发利器,通过通信来实现内存共享而不是通过共享内存来通信,本篇从了解Go的并发哲学、理论及并发原语开始,之后用一个个Go代码示例认识Go的协程、通道、定时器、互斥锁、池化、原生操作等十几个并发编程... 查看详情

go-并发编程基础(goroutinechannelselect等)(代码片段)

...hannelchannel中的channel常见错误time与select超时时间间隔概念并发:指宏观上在一段时间内能同时运行多个程序,微观上交替运行。并行:指同一时刻能运行多个指令。进程:一段程序的执行 查看详情

go编程基础(代码片段)

什么是Go?Go是一门并发支持、垃圾回收的编译型系统编程语言,旨在创造一门具有在静态编译语言的高性能和动态语言的高效开发之间拥有良好平衡点的一门编程语言。Go的主要特点:类型安全和内存安全以非常直观和极低代价... 查看详情

图解go并发(代码片段)

...强大的社区支持。学习这门语言最令人兴奋的一点是它的并发模型。Go的并发原语使创建多线程并发程序变得简单而有趣。我将通过插图介绍Go的并发原语,希望能点透相关概念以方便后续学习。本文是写给Go语言编程新手以及准... 查看详情

go基础之文件操作命令行参数序列化并发编程(代码片段)

Go基础(三)之文件操作、命令行参数、序列化、并发编程一、文件操作1.1打开和关闭文件1.2读取文件1.2.1按字节读取:file.Read()1.2.2bufio按行读取文件1.2.3ioutil读取整个文件1.3文件写入1.3.1Write和WriteString1.3.2bufio.NewWriter1... 查看详情

go笔记(十五):并发编程(代码片段)

一、协程的创建  Go语言支持并发,只需要通过go关键字来开启goroutine(协程)即可。  goroutine(协程)是轻量级线程,goroutine(协程)的调度是由Golang运行时进行管理的。goroutine语法格式(创建协程):go函数名(参数列表)示例代码如... 查看详情

go并发编程byexamples(代码片段)

...://liushiming.cn/2020/01/21/concurrent-programming-in-go-by-examples/概述并发是go的一个吸引开发者的特性,也是一个难点,以下整理自我在公司的一个内部分享,全部都是以示例的形式进行说明,有兴趣跑一下就掌握了。本文中的代码在github... 查看详情