go关于并发编程的操作

这篇具有很好参考价值的文章主要介绍了go关于并发编程的操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  1. 多线程程序在一个核的CPU运行

image.png

  1. 多线程程序在多个核的CPU运行

image.png
image.png

goroutine

协程:用户态,轻量级线程,栈KB级别,创建和调度由go语言直接调度
线程:内核态,线程跑多个协程,栈MB级别

package main

import (
    "fmt"
    "time"
)

func hello(i int) {
    println("hello goroutine: " + fmt.Sprint(i))
}
func hello_goroutine() {
    for i := 0; i < 5; i++ {
        go func(j int) {
            hello(j)
        }(i)
    }
    time.Sleep(time.Second)
}

image.png
go关键字直接可以开启新的协程

CSP模型

image.png
CSP 是 Communicating Sequential Process 的简称,中文可以叫做通信顺序进程,是一种并发编程模型,是一个很强大的并发数据模型,是上个世纪七十年代提出的,用于描述两个独立的并发实体通过共享的通讯 channel(管道)进行通信的并发模型。相对于Actor模型,CSP中channel是第一类对象,它不关注发送消息的实体,而关注与发送消息时使用的channel。
Golang 就是借用CSP模型的一些概念为之实现并发进行理论支持,其实从实际上出发,go语言并没有,完全实现了CSP模型的所有理论,仅仅是借用了 process和channel这两个概念。process是在go语言上的表现就是 goroutine 是实际并发执行的实体,每个实体之间是通过channel通讯来实现数据共享。
Go语言的CSP模型是由协程Goroutine与通道Channel实现:

  • Go协程goroutine: 是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度。是一种绿色线程,微线程,它与Coroutine协程也有区别,能够在发现堵塞后启动新的微线程。
  • 通道channel: 类似Unix的Pipe,用于协程之间通讯和同步。协程之间虽然解耦,但是它们和Channel有着耦合。

channel

make (chan元素类型,「缓冲模型」)

  1. 有缓冲通道 make(chan int)
  2. 无缓冲通道 make(chan int,2)

image.png
goroutine 和 channel 是 Go 语言并发编程的 两大基石。Goroutine 用于执行并发任务,channel 用于 goroutine 之间的同步、通信。
Channel 在 gouroutine 间架起了一条管道,在管道里传输数据,实现 gouroutine 间的通信;由于它是线程安全的,所以用起来非常方便;channel 还提供 “先进先出” 的特性;它还能影响 goroutine 的阻塞和唤醒。
不要通过共享内存来通信,而要通过通信来实现内存共享。
这就是 Go 的并发哲学,它依赖 CSP 模型,基于 channel 实现。
因为 channel 是一个引用类型,所以在它被初始化之前,它的值是 nil,channel 使用 make 函数进行初始化。可以向它传递一个 int 值,代表 channel 缓冲区的大小(容量),构造出来的是一个缓冲型的 channel;不传或传 0 的,构造的就是一个非缓冲型的 channel。
两者有一些差别:非缓冲型 channel 无法缓冲元素,对它的操作一定顺序是 “发送 -> 接收 -> 发送 -> 接收 -> ……”,如果想连续向一个非缓冲 chan 发送 2 个元素,并且没有接收的话,第一次一定会被阻塞;对于缓冲型 channel 的操作,则要 “宽松” 一些,毕竟是带了 “缓冲” 光环。
对 chan 的发送和接收操作都会在编译期间转换成为底层的发送接收函数。
Channel 分为两种:带缓冲、不带缓冲。对不带缓冲的 channel 进行的操作实际上可以看作 “同步模式”,带缓冲的则称为 “异步模式”。
同步模式下,发送方和接收方要同步就绪,只有在两者都 ready 的情况下,数据才能在两者间传输(后面会看到,实际上就是内存拷贝)。否则,任意一方先行进行发送或接收操作,都会被挂起,等待另一方的出现才能被唤醒。
异步模式下,在缓冲槽可用的情况下(有剩余容量),发送和接收操作都可以顺利进行。否则,操作的一方(如写入)同样会被挂起,直到出现相反操作(如接收)才会被唤醒。

package main

func CalSquare() {
	src := make(chan int)
	dest := make(chan int, 3)

	go func() {
		defer close(src)
		//Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,
		//在 defer 归属的函数即将返回时,将延迟处理的语句按 defer
		//的逆序进行执行,也就是说,先被 defer 的语句最后被执行,
		//最后被 defer 的语句,最先被执行。

		for i := 0; i < 10; i++ {
			src <- i
		}
	}()
	go func() {
		defer close(dest)
		for i := range src {
			dest <- i * i
		}
	}()
	for i := range dest {
		println(i)
	}
}

func main() {
	CalSquare()
}


chan T // 声明一个双向通道
chan<- T // 声明一个只能用于发送的通道
<-chan T // 声明一个只能用于接收的通道COPY

并发安全锁

Eg:对变量执行2000次+1的操作,5个协程并发进行

package main

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

var (
	x    int64
	lock sync.Mutex
)

func addWithLock() {
	for i := 0; i < 2000; i++ {
		lock.Lock()
		x += 1
		lock.Unlock()
	}
}

func addWithoutLock() {
	for i := 0; i < 2000; i++ {
		x += 1
	}
}
func add() {
	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutLock()
	}
	time.Sleep(time.Second)
	fmt.Println("without lock", x)

	x = 0
	for i := 0; i < 5; i++ {
		go addWithLock()
	}
	time.Sleep(time.Second)
	fmt.Println("with lock", x)

}

func main() {
	add()
}

image.png

waitgroup

WaitGroup是Go语言中的一个类型,它可以用来等待一组Go协程完成。它有三个方法:Add,Done和Wait。Add方法用于将要等待的Go协程数量添加到WaitGroup中;Done方法用于通知WaitGroup一个Go协程已经完成;Wait方法用于阻塞当前Go程,直到WaitGroup内的Go协程都完成。
image.png

func manytowait() {
	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0; i < 5; i++ {
		go func(j int) {
			defer wg.Done()
			hello(j)
		}(i)
	}
	wg.Wait()
}

1、 Add一个负数
如果计数器的值小于0会直接panic

2、 Add在Wait之后调用
比如一些子协程开头调用Add结束调用Wait,这些 Wait无法阻塞子协程。正确做法是在开启子协程之前先Add特定的值。

3、 未置为0就重用
WaitGroup可以完成一次编排任务,计数值降为0后可以继续被其他任务所用,但是不要在还没使用完的时候就用于其他任务,这样由于带着计数值,很可能出问题。

4、 复制waitgroup
WaitGroup有nocopy字段,不能被复制。也意味着WaitGroup不能作为函数的参数文章来源地址https://www.toymoban.com/news/detail-465833.html

到了这里,关于go关于并发编程的操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 学习如何在VS Code中创建一个Golang/Go项目,并运行一个简单的Golang程序

     学习如何在VS Code中创建一个Golang项目,并运行一个简单的Golang程序。 在VS Code 手动输入命令创建一个Golang项目 在VS Code 不输入命令创建一个Golang项目 1. 在VS Code 手动输入命令创建一个Golang项目 步骤1:在VS Code中创建一个新文件夹,用于存放Golang项目文件。 步骤2:打开VS

    2024年02月14日
    浏览(45)
  • 并发编程(高并发、多线程)

    1.1.1 并发编程三要素 首先我们要了解并发编程的三要素 原子性 可见性 有序性 1.原子性 原子性是指一个操作是不可分割的单元,要么全部执行成功,要么全部失败。 在并发环境中,多个线程可能同时访问和修改共享的数据,为了确保数据的一致性,需要确保一组相关的操作

    2024年02月04日
    浏览(27)
  • GO语言网络编程(并发编程)并发介绍,Goroutine

    进程和线程 并发和并行 协程和线程 协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。 线程:一个线程上可以跑多个协程,协程是轻量级的线程。 goroutine 只是由官方实现的超级\\\"线程池\\\"。 每个

    2024年02月09日
    浏览(30)
  • 16 Go并发编程(三): Go并发的传统同步机制

    Go 传统同步机制 在《Go并发编程初探》中我们提到同步概念,所谓同步是相对异步而言,即串行相对于并行。 在学习Go通信机制时我们知道管道其实就是并发单元同步方式的一种,基于CSP并发模型,Go在语言原语上使管道作为核心设计,这是Go的设计哲学,也是Go所提倡的同步

    2023年04月08日
    浏览(26)
  • 多线程并发编程-线程篇

    系统中的一个程序就是一个进程,每个进程中的最基本的执行单位,执行路径就是线程,线程是轻量化的进程。 绿色线程,由用户自己进行管理的而不是系统进行管理的,我理解就是一个进程里面可以有多线程,一个线程里面有多进程(go里面叫协程) 线程是按照CPU分的时间

    2023年04月21日
    浏览(26)
  • go中数组、切片、map是否线程(并发)安全?

    博客主页:🏆 看看是李XX还是李歘歘  🏆 🌺每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点,以及职场小菜鸡的生活。🌺 💗 点关注不迷路,总有一些📖知识点📖是你想要的 💗  目录 什么是线程(并发)安全? 非线程安全原因 map 解决方案

    2024年02月02日
    浏览(43)
  • C# 关于使用newlife包将webapi接口寄宿于一个控制台程序、winform程序、wpf程序运行

    C# 关于使用newlife包将webapi接口寄宿于一个控制台程序、winform程序、wpf程序运行 安装newlife包 Program的Main()函数源码 MyController 源码 MyHttpHandler 源码 源代码百度链接 链接:https://pan.baidu.com/s/15OxTDOBO_y5bFyrzPW3XPw?pwd=sr3c 提取码:sr3c

    2024年02月15日
    浏览(35)
  • Java并发(四)----线程运行原理

    1.1 栈与栈帧   Java Virtual Machine Stacks (Java 虚拟机栈 JVM) 我们都知道 JVM 中由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机就会为其分配一块栈内存。 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存 每个

    2024年02月02日
    浏览(25)
  • 多线程与高并发——并发编程(5)

    为什么要使用线程池? 在开发中,为了提升效率,我们需要将一些业务采用多线程的方式去执行。比如,有一个比较大的任务,可以将任务分成几块,分别交给几个线程去执行,最终做一个汇总即可。再比如,做业务操作时,需要发送短信或邮件,这些操作也可以基于异步的

    2024年02月09日
    浏览(33)
  • 多线程与高并发——并发编程(4)

    1.1 生产者消费者概念 生产者-消费者是设计模式的一种,让生产者和消费者基于一个容器来解决强耦合的问题。生产者与消费者彼此之间不会直接通讯,而是通过一个容器(队列)进行通讯。 生产者生产完数据后扔到容器中,不用等消费者来处理; 消费者也不需要去找生产

    2024年02月10日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包