Go并发(多任务)时如何进行同步? 如何数据互通? 图文讲解 [_]~( ̄▽ ̄)~* Go相关

2023-05-16

文章目录

  • Go并发
    • 同义说明
  • Go并发基础
    • 主线程与go程
    • 等待go程与`同步(sync)`
    • go程通讯与`管道(channel)`
      • 关闭管道

Go并发

Go的并发官方称其为goroutine, 我们可以将它看成为一个轻量级的线程(在其他语言中常用thread来表示线程相关的库), 他相比于其他语言的多线程更易用、更高效、更轻便。
调用Go的多线程非常简单,只需要使用关键字Go即可。但要使用好Go的多线程,实现各种功能,我们就需要Go的标准库同步(sync)与上下文(context)的配合。

同义说明

goroutine, go程, 轻量级线程: 下述中我主要这些都是一个东西,都是表示go中特有的一种并发模式。
context, ctx, 上下文: 都为同一种东西

Go并发基础

主线程与go程

go程是依附于主线程的, 这个依主要附体现在与主线程共存亡, 也就是说主线程一旦结束, go程无论是否执行完毕都会被结束掉。刚接触并发时非常容易出现没有调节好主线程的结束时间,导致go程还未运行结束就被迫结束的问题。
在这里插入图片描述

package main

import (
	"fmt"
)

func 测试线程(起始, 结束 int) {
	for i := 起始; i < 结束; i++ {
		fmt.Println("*-*: ", i)
	}
	fmt.Println("--------------分割线--------------")
}

func main() {
	for i := 0; i < 3; i++ {
		go 测试线程(0, 2)
	}
	测试线程(10, 12)
}

在这里插入图片描述
如上代码, 从执行结果可以看出, 我们的go程只运行了两次,就会因为主进程的结束而被迫结束。(多次执行结果都会不同, 甚至可能会出现go程一次都未执行的情况)
想要解决这个问题最直接的方法,就是让主线程停下来,等等其他线程,其中最笨拙的方法无疑是直接使用睡眠函数,让线程沉睡一会。

func main() {
	for i := 0; i < 3; i++ {
		go 测试线程(0, 2)
	}
	测试线程(10, 12)
	time.Sleep(1000 * time.Millisecond)
}

等待go程与同步(sync)

标准库-同步(sync),提供了一种方法可以让主线程在go程未完成前停下等待。
sync.WaitGroup: Add(数量)等待组添加指定等待数量; Done()减少一个等待数量; Wait: 停下等待等待组清零后在继续执行。

package main

import (
   "fmt"
   "sync"
)

var 等待组 sync.WaitGroup

func 测试线程(起始, 结束 int, gobool) {
   if go{
   	defer 等待组.Done()
   }
   for i := 起始; i < 结束; i++ {
   	fmt.Println("*-*: ", i)
   }
   fmt.Println("--------------分割线--------------")
}

func main() {
   for i := 0; i < 3; i++ {
   	等待组.Add(1)
   	go 测试线程(0, 2, true)
   }
   测试线程(10, 12, false)
   等待组.Wait()
}

在这里插入图片描述
这样无论运行多少次, 主线程都会等待go程运行结束后在结束整个进程

go程通讯与管道(channel)

并发中还有一个让人十分头疼的问题,就是不同线程之间的变量传参问题, 解决这个问题, 主要会用到Channel(管道), 这是Go中的一个核心类型其地位类似数组(slice), 散列(map)这样的类型,使用非常便捷。

// 创建管道(无缓存)
var 管道 = make(chan 类型)
var 字符管道 = make(chan string)
var 列表管道 = make(chan []string)
// 创建管道(有缓存)
var 缓存整数管道 = make(chan int, 5)

使用无缓冲的管道时,必须确保在传入值时,必须先有一个以上的函数等待通道传输,否则会报如下错误fatal error: all goroutines are asleep - deadlock!(大致意思就是说没找到相关的go程,你这样操作会产生死锁)不带缓冲的管道, 你就可以将其看为一个水管, 流入水必须要有一个以上出口, 否则是无法正常流入其中的。

//管道可以传入任何类型, 包括管道, 比如: <-chan(<-chan string)
func 接收管道(字符 <-chan string) {
	for {
		fmt.Printf("从管道传入了一个:%v\n", <-字符)
	}
}

// 这里如果使用  chan string  则代表为双向管道既可以接收值又可以发送 
func 发送管道(字符 chan<- string) {
	字符 <- "寻觅的"
}

func main() {
	var 管道 = make(chan string)
	go 接收管道(管道)
	发送管道(管道)
	管道 <- "觅库"
	time.Sleep(100 * time.Millisecond)
}

在这里插入图片描述

都没有缓存区的管道, 如果在同一个函数内同时发送和接受就会出现报错, 因为同一个函数内执行的往往是从上到下按顺序执行的, 你在发送的同时不可能做到接收, 反之同理。如果想要缓冲池也很简单,只需要在建立通道的时候标注需要一个多大的缓冲池即可make(chan 类型, 缓冲大小)
在这里插入图片描述

func 双向管道(列表 chan []string) {
	列表 <- []string{"测试1", "测试2"}
	fmt.Println("输出双向管道", <-列表)
}

func main(){
	var 列表管道 = make(chan []string, 1)
	go 双向管道(列表管道)
	time.Sleep(1000 * time.Millisecond)
}

在这里插入图片描述

关闭管道

go中的管道是可以关闭的, 使用close()即可关闭, 不过需要注意的是go关闭管道并不是将管道彻底销毁, 而是相当于将管道的入口阀给封闭, 管道本身还是存在的, 并且如果你是一个带有缓存区的管道, 其缓存区内的数值还是能正常读取的!

func 双向管道(列表 chan []string) {
	列表 <- []string{"测试3", "测试4"}
	fmt.Println("输出双向管道", <-列表)

	//列表 <- []string{"测试1", "测试2"}
	close(列表)
	// 这样写可以用来检测当前管道中是否有值, ok为flase的条件是管道中没有值,切执行了close(缺一不可)
	测试, ok := <-列表
	fmt.Println(ok)
	if ok {
		fmt.Println(测试, ok)
	}
}

func main(){
	var 列表管道 = make(chan []string, 1)
	go 双向管道(列表管道)
	time.Sleep(1000 * time.Millisecond)
}

如上述代码所示, 关闭管道后,我们还能正常读取管道内的值, 但是无法在向管道内添加值了, 否则会报错panic: send on closed channel
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go并发(多任务)时如何进行同步? 如何数据互通? 图文讲解 [_]~( ̄▽ ̄)~* Go相关 的相关文章

  • 【PX4代码】关于px4代码中timestamp与gps_itow的时间问题

    gps的输出频率为5hz xff0c 由此可见timestamp应该是113248090 1e 6转换为s xff0c 由次可见gps的itow时间应该为271998999 1e 3转换为s 总结 px4中的时间为cpu应该除以10 6 x
  • 【PX4代码】关于ekf2输出频率只有1ohz的问题

    问题 我在使用的是pixhawk 2代 imu的输出频率都在100hz以上 xff0c 使用的gps模块输出频率为5hz xff0c 使用log的local position csv 查看ekf2估计输出的点位信息只有10hz xff0c
  • Keil4中C51的debug调试步骤技巧

    1 选择相应的调试仿真连接器 xff1a 选择 xff1a project gt Options for Target 如下图所示 xff1a 然后在弹出对话框的Debug选项下选择仿真器的型号 xff1a 2 进入调试 xff1a 3 部
  • 怎么操作linux服务器

    Linux 服务器就是采用 Linux 系统的网络服务器 xff0c 同时也有采用 windows 的服务器 xff0c 作用是类似的 而 Linux 并不是一个特定的系统 xff0c 而是使用 Linux 内核的系统 xff0c 现在发行
  • 人工智能如何可以思考?

    近日在给同事讲人工智能的时候 xff0c 提到当数据量不够的时候 xff0c 必要时需要加入人工工程 xff0c 引导计算机 归纳 一些知识 xff0c 毕竟计算机智能比起人类智能 xff0c 最大的缺陷可能在于不懂得 举一反三 换句话说
  • bag文件内topic对应的frame_id查看指令

    启动ROS roscore 运行数据集 span class token comment 数据集小的话 xff0c 建议慢速播放 span rosbag play xxx span class token punctuation span
  • GPS数据类型(ROS)

    文章目录 一 传感器分类二 作用三 系统组成四 位置表示五 数据格式六 ROS中GPS数据格式sensor msgs NavSatFixROS中GPS数据主要包含这四类 xff0c 分别是gps 裸数据ros封装 xff0c 位置 xff0
  • cmake使用教程

    CMakeLists txt文档编写以及packsge xml文档介绍 CMakeLists txt文档一 cmake minimum required命令二 CMake中的编译类型三 cmake编译选项 xff08 与2对应 xff09
  • 四旋翼无人机飞控系统设计(闭环控制系统)

    对于一个简单的飞控程序来说 xff0c 控制器是它最核心的部分 xff0c 这里主要与大家讨论控制系统的基本理论知识 xff08 自控大佬请绕道 xff09 xff0c 包括控制系统概念 闭环控制系统的原理 下篇将侧重包含pid控制算法的具
  • 针对frame_id和child_frame_id的理解

    ros基础必看之各个frame的理解 ROS坐标系统 xff0c 常见的坐标系和其含义 ROS中TF 坐标系转换 原理与使用
  • IMU预积分学习

    IMU预积分学习 一 IMU状态传递方程 一 IMU状态传递方程 几种不同的表达形式 xff1a 1 lio mapping xff1a 参考大佬 xff1a lio mapping 及 VINS Mono代码及理论推导 xff08 2 x
  • Python3 内置模块 - os

    方法名说明os access判断文件权限os chdir改变当前工作目录os chmod file 修改文件权限os execvp 启动一个新进程os execvp 执行外部程序脚本 xff08 Uinx xff09 os fork 获取父
  • AttributeError: module 'tornado.web' has no attribute 'asynchronous'解决方法

    AttributeError module tornado web has no attribute 39 asynchronous 解决方法 今天看tornado异步时发现的错误 xff0c 查了一下 xff0c 原来tornado6以后
  • 【STM32项目】- 人体检测(体温、心率、心跳、跌倒检测)

    STM32人体检测 xff08 体温 心率 心跳 跌倒检测 xff09 43 zigbee 笔者前言 在闲鱼有缘结识的一个哥们 xff0c 帮助做的基于STM32人体检测系统 xff0c 我负责硬件程序开发设计 xff0c 哥们负责客户端服
  • ESP32 之 esp32-cam wifi拍照传图系统1

    文章目录 ESP32 之 esp32 cam wifi拍照传图系统1 效果演示2 材料准备3 原理图接线4 下载代码 ESP32 之 esp32 cam wifi拍照传图系统 1 效果演示 2 材料准备 ESP32 camUSB转TTL按钮
  • ESP32 之 esp32-cam wifi拍照传图系统2

    ESP32 之 esp32 cam wifi拍照传图系统 补充说明 ESP32 CAM总结 一 ESP32初识 ESP32 CAM模组的核心芯片 xff1a ESP32 S 模块是一款超小体积的多功能通用型 802 11b g n WiFi
  • 【PX4 飞控二次开发】第一个程序 打印输出-模拟

    第一个程序 1 编写任务代码 Cmake文件2 编译 1 编写任务代码 Cmake文件 span class token operator span span class token operator span PIX4 span clas
  • 【PX4 飞控二次开发】UORB 发布及订阅自定义

    UORB测试 一 添加msg1 创建 msg文件2 Cmakelists txt修改3 编译错误4 编译成功 二 发布及订阅主题1 添加代码2 修改cmake3 再次编译 一 添加msg 1 创建 msg文件 span class toke
  • 【PX4 飞控二次开发】自制ESP8266WIFI数传

    ESP8266数传模块 一 简介二 下载烧录固件1 下载MavLink ESP8266固件2 烧录 三 连线四 配置ESP8266五 连接WIFI Bridge 一 简介 ESP8266是一款低成本 xff0c 易于使用的Wi Fi模块 x
  • 四旋翼无人机飞控系统设计(PID控制算法)

    PID控制算法 PID控制器是一个结构简单并且成熟稳定的控制器 xff0c 在工业上应用广泛 包括比例 xff08 Proportion xff09 积分 xff08 Integral xff09 微分 xff08 Differential

随机推荐