【gogogo专栏】golang并发编程

golang并发编程

  • 并发编程的工具
    • goroutine介绍
      • 协程管理器sync.WaitGroup
    • channel介绍
      • readChannel和writeChannel
      • close的用法
      • select的用法
  • 通讯示例
  • 总结

并发编程的工具

在golang中,并发编程是比较简单的,不像java中那么麻烦,golang天然的支持协程(线程)的管理,通常用goroutine和channel来管理go的并发编程。

goroutine介绍

goroutine在go语言中叫做协程,相当于java中线程的概念,使用起来也非常简单,在方法前面加个go就行了。

go Run() 例如这样就是开启一个新的协程去跑Run方法

协程管理器sync.WaitGroup

在使用协程时,如果主线程结束的时候,我们并不能知道协程里面发生了什么,也无法控制它,因此引入了sync.WaitGroup,来控制协程。
我们来看以下这个例子,在协程启动的时候开启了一个协程WaitGroup,当Add里面有数字的时候,当数字减到0才能结束。

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go Run(&wg)
	wg.Wait()
}

func Run(wg *sync.WaitGroup) {
	fmt.Println("我跑起来了")
	wg.Done()
}

我们首先测试一下方法

wg.Add(1) ===> 输出结果:我跑起来了
wg.Add(0) ===> 输出结果:空
wg.Add(2) ===> 输出结果:我跑起来了 fatal error: all goroutines are asleep - deadlock!

我们可以看到这里有个报错,在 main 函数中使用了 wg.Wait() 来等待两个协程完成任务,但是在 Run 函数中,你只是调用了 wg.Done() 来通知 WaitGroup 任务完成,但是没有关闭等待。
因此推荐以下这种写法,比较安全,保证最终关闭等待。

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		Run()
	}()

	go func() {
		defer wg.Done()
		Run()
	}()

	wg.Wait()
}

func Run() {
	fmt.Println("我跑起来了")
}

channel介绍

channel是用来负责协程之间的通信的,可以理解为一个管道,我们首先举一个最简单的例子,箭头表示读取,这样就表示往管道里面读入和获取一个数了。

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

c1 := make(chan int, 1) 这里的1代表缓冲区的容量,当有缓冲区的时候,存入数据会预先存进缓冲区,当需要的时候再取出。当c1 := make(chan int) 这样写的时候,则代表没有容量,写入的时候会阻塞,除非有其他goroutine进行消费,否则无法执行下一步操作。

因此调用下面这个方法则会造成死锁。

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

但是如果是异步执行的话则可以正常执行获取,因为这个写入的操作跑到另一个cpu线程(时间分片)上去了,不会对主线程造成阻塞,当主线程去获取这个值的时候,则可以顺利拿到。

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

下面我们再来看看缓冲区这个概念,以下面这段代码为例,无缓冲区时,向channel中存入则阻塞,有缓冲区时更像一种生产者消费者模型,充满缓冲区才阻塞。

func main() {
	//c1 := make(chan int)
	//c1 := make(chan int, 5)
	c1 := make(chan int, 10)

	go func() {
		for i := 0; i < 10; i++ {
			c1 <- i
		}
	}()

	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		fmt.Println(<-c1)
	}
}

我们在这里打上断点可以很明显的看到变化。
在这里插入图片描述

readChannel和writeChannel

在channel中可以定义可读和可写channel

func main() {
	c1 := make(chan int, 5)
	var read <-chan int = c1
	var write chan<- int = c1
	write <- 1
	fmt.Println(<-read)
}

close的用法

close可以关闭一个channel,使其无法往里面写,但是仍然可以往里面读。

func main() {
	c1 := make(chan int, 5)
	c1 <- 1
	c1 <- 2
	c1 <- 3
	c1 <- 4
	c1 <- 5
	close(c1)
	fmt.Println(<-c1)
	fmt.Println(<-c1)
	fmt.Println(<-c1)
	fmt.Println(<-c1)
	fmt.Println(<-c1)
}

此时不用close也是可以执行的,但是当我们使用循环取的时候,必须要用close。

func main() {
	c1 := make(chan int, 5)
	c1 <- 1
	c1 <- 2
	c1 <- 3
	c1 <- 4
	c1 <- 5
	close(c1)
	for v := range c1 {
		fmt.Println(v)
	}
}

select的用法

我们以一下代码为例

func main() {
	c1 := make(chan int, 1)
	c2 := make(chan int, 1)
	c3 := make(chan int, 1)
	c1 <- 1
	c2 <- 1
	c3 <- 1
	select {
	case <-c1:
		fmt.Println("c1")
	case <-c2:
		fmt.Println("c2")
	case <-c3:
		fmt.Println("c3")
	default:
		fmt.Println("都没执行")
	}
}

使用select可以将能执行的都执行,比如上面的代码执行顺序就是三个case随机一个或全部执行。

通讯示例

func main() {
	var wg sync.WaitGroup
	wg.Add(2) // 增加等待组计数器,表示有两个协程需要等待

	ch := make(chan int) // 创建整数类型的通道

	go producer(ch, &wg) // 启动生产者协程
	go consumer(ch, &wg) // 启动消费者协程

	wg.Wait() // 等待所有协程执行完毕
}

func producer(ch chan int, wg *sync.WaitGroup) {
	defer wg.Done()

	for i := 0; i < 10; i++ {
		fmt.Println("Produced:", i)
		ch <- i
	}

	close(ch) // 关闭通道,表示生产者完成生产
}

func consumer(ch chan int, wg *sync.WaitGroup) {
	defer wg.Done()

	for data := range ch {
		fmt.Println("Consumed:", data)
	}
}

我们可以通过这种方式实现一个简单的生产者消费者模型来实现线程交互。

总结

在go语言中,我们完全可以通过goroutine和channel实现线程之间的通讯,来实现协程之间协调。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/122288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

希尔排序原理

目录&#xff1a; 一、希尔排序与插入排序 1&#xff09;希尔排序的概念 2&#xff09;插入排序实现 二、希尔排序实现 一、希尔排序与插入排序 1&#xff09;希尔排序的概念 希尔排序(Shells Sort)是插入排序的一种又称“缩小增量排序”&#xff08;Diminishing Incremen…

ChineseChess.2023.11.09.01

中国象棋残局模拟器ChineseChess.2023.11.09.01

【PC】特殊空投-2023年11月

亲爱的玩家朋友们&#xff0c;大家好&#xff01; 寒冷的11月&#xff0c;特殊空投活动来袭。从连续签到活动到神秘市场相关活动&#xff0c;我们已经为大家准备好了一切&#xff0c;只为给大家在这寒冷的11月带来一份暖意。还有大量的黑货票劵等着大家&#xff0c;请一定要领取…

C语言-调试文件

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> //读256 a 256 fseek 改文件&#xff0c;用ocd&#xff0c;先搞b5v0 int main(int argc, char **argv) {if (argc ! 2) return -1;char file_buf[256];FILE* file1 fopen(argv[1], …

前后端交互常见的几种数据传输格式 form表单+get请求 form表单+post请求 json键值对格式

目录 1. get请求 query string 2.form表单get请求 3..form表单post请求 4..json格式 5.总结 1. get请求 query string 前端通过get请求携带 query string&#xff08;键值对&#xff09; ,后端通过req.getParameter(key)方法获取数据。如果key不存在&#xff0c;获取到的就…

pyspark将数据多次插入表的时候报错

代码 报错信息 py4j.protocol.Py4JJavaError: An error occurred while calling o129.sql. : org.apache.spark.sql.catalyst.parser.ParseException: mismatched input INSERT expecting <EOF>(line 12, pos 0) 原因 插入语句结束后没有加&#xff1b;结尾 把两个&am…

ROS学习笔记(6):ros_control

1.ros_control简介 ros_control - ROS Wiki ros_control是为ROS提供的机器人控制包&#xff0c;包含一系列控制器接口、传动装置接口、控制器工具箱等,有效帮助机器人应用功能包快速落地&#xff0c;提高开发效率。 2.ros_control框架 ros_control总体框架&#xff1a; 针对…

python连接mysql进行查询

pymysql连接工具类 import pymysql 数据库连接工具类 class MySQLConnection:def __init__(self, host, port, user, password, database):self.host hostself.port portself.user userself.password passwordself.database databaseself.conn Noneself.cursor None# …

广域网加速的作用:企业为什么需要广域网加速?

由于局域网与广域网之间巨大的带宽鸿沟&#xff0c;通过增加带宽来满足膨胀的流量需求是不切实际的。 并且广域网带宽成本较高&#xff0c;增加广域网带宽对任何企业都意味着巨大的成本负担。这些使得控制 管理广域网带宽使用成为必需。 企业为什么要加速广域网? 对重要的企…

微信小程序案例3-2 计算器

文章目录 一、运行效果二、知识储备&#xff08;一&#xff09;data-*自定义属性&#xff08;二&#xff09;模块 三、实现步骤&#xff08;一&#xff09;准备工作&#xff08;二&#xff09;实现页面结构&#xff08;三&#xff09;实现页面样式&#xff08;四&#xff09;实…

Debian12换镜像源

0 背景 用docker运行了一个node容器&#xff0c;发现连vim也没有&#xff0c;所以打算安一个vim 1 查看操作系统 find / -name *release* #查看release信息2 更换镜像源 2.1 从网上找个国内镜像源 确定好操作系统版本后&#xff0c;从网上搜一下对应的数据源。这里提供一个…

Ubuntu20.0工作区(workspace)介绍,切换工作区方式和快捷键

Ubuntu20.0工作区&#xff08;workspace&#xff09;介绍&#xff0c;切换工作区方式和快捷键 先修改一下ubuntu截屏的快捷键查看工作区新建工作区工作区切换 先修改一下ubuntu截屏的快捷键 修改为 查看工作区 按下Super键&#xff08;即Windows键&#xff09;&#xff0c;可…

动态壁纸软件Live Wallpaper HD mac中文版功能特色

Live Wallpaper HD mac提供了一系列美丽的主题场景&#xff0c;将为您的桌面增添活力。从城市景观、日落到遥远的星系&#xff0c;每个屏幕都有特别的触感&#xff0c;可以定制您的天气小部件和时钟样式&#xff0c;并使用您喜爱的图片创建您自己的个性化壁纸。 Living Wallpap…

安装dubbo-admin报错node版本和test错误

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;dubbo-admin安装 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0…

5G毫米波通信中的关键技术

随着5G技术的快速发展&#xff0c;毫米波通信作为其中的一项重要技术&#xff0c;在高速数据传输、低延迟通信和大规模连接等方面具有显著的优势。本文将探讨5G毫米波通信中的关键技术&#xff0c;包括毫米波频段的选择、信号处理技术和MIMO技术等。 一、毫米波频段的选择 毫米…

Selenium alert 弹窗处理!

页面弹窗有 3 种类型&#xff1a; alert&#xff08;警告信息&#xff09;confirm&#xff08;确认信息&#xff09;prompt&#xff08;提示输入&#xff09; 对于页面出现的 alert 弹窗&#xff0c;Selenium 提供如下方法&#xff1a; 序号方法/属性描述1accept()接受2dismis…

查分小程序,教学大作用

数字化时代&#xff0c;技术已经深深的改变了我们的生活和工作方式。当然&#xff0c;教育领域也不例外。如果你是一位老师&#xff0c;你可能会想知道如何利用这些技术工具来提高学生的学习体验和成绩。今天&#xff0c;我们就来聊聊如何用各种代码、Excel等工具&#xff0c;打…

systemd-journald日志管理服务详解

journald参考文档&#xff1a; journald.confhttps://www.freedesktop.org/software/systemd/man/latest/journald.conf.html Amazonlinux2023系统默认不再安装rsyslog&#xff0c;因此在amazonlinux2中的诸多日志文件例如/var/log/message默认不可用。 AWS官方文档建议使用sys…

在Kotlin中设置User-Agent以模拟搜索引擎爬虫

前言 随着双十一电商活动的临近&#xff0c;电商平台成为了狂欢的中心。对于商家和消费者来说&#xff0c;了解市场趋势和竞争对手的信息至关重要。在这个数字时代&#xff0c;爬虫技术成为了获取电商数据的有力工具之一。本文将以亚马逊为例&#xff0c;介绍如何使用Kotlin编…

Git的安装和常用命令Git与SVN的区别Gitee远程仓库团队开发代码共享演示

目录 一、Git入门 1.1 Git简介 1.2 Git与SVN的区别 1.2.1 详解 1.2.2 图解 1.3 Git相较于SVN的优势与劣势 1.3.1 Git的优势与劣势 1.3.2 SVN的优势与劣势 1.4 Git的工作流程 1.4.1 图解 1.4.2 详解 二、Git的安装以及常用命令 2.1 Git官网链接 2.2 安装步骤 2.…