如何在Go中并发运行多个函数

news2024/11/24 9:03:08

引言

Go语言的一个流行特性是它对并发的一流支持,即一个程序可以同时做多件事。随着计算机从更快地运行单个代码流转向同时运行更多代码流,能够并发地运行代码正在成为编程的重要组成部分。为了让程序运行得更快,程序员需要把程序设计成并发运行,这样程序中并发的每一部分都可以独立于其他部分运行。Go中的两个特性,goroutines和channels,在一起使用时使并发更容易。协程解决了在程序中设置和运行并发代码的困难,通道解决了并发运行的代码之间安全通信的困难。

在本教程中,你将探索goroutines和channels。首先,你将创建一个使用goroutines一次运行多个函数的程序。然后,您将向该程序添加通道,以便在运行的goroutines之间进行通信。最后,你将向程序中添加更多的goroutines,以模拟程序在多个worker goroutines下运行。

与Goroutines同时运行函数

在现代计算机中,处理器(CPU)被设计成同时运行尽可能多的代码流。这些处理器有一个或多个“核心”,每个核心能够同时运行一个代码流。因此,程序可以同时使用的内核越多,程序运行得就越快。然而,为了让程序利用多核带来的速度提升,程序需要能够拆分为多个代码流。将程序拆分为多个部分可能是编程中最具挑战性的事情之一,但Go的设计使这一过程更容易。

一种方法是使用** goroutines 功能。goroutine是一种特殊类型的函数,它可以在其他goroutine运行时运行。当一个程序被设计为一次运行多个代码流时,该程序被设计为并发**运行。通常,当函数被调用时,它将在代码继续运行之前完全运行完毕。这被称为在“前台”运行,因为它阻止程序在完成之前做任何其他事情。使用goroutine,当goroutine在“后台”运行时,函数调用将继续立即运行下一段代码。当代码在完成之前不阻止其他代码运行时,就认为它在后台运行。

goroutines提供的功能是每个goroutine可以同时在一个处理器内核上运行。如果您的计算机有四个处理器内核,并且您的程序有四个goroutines,所有四个goroutines可以同时运行。当多个代码流同时在不同的内核上运行时,我们称之为并行运行。

为了可视化并发和并行之间的区别,请考虑下面的图。当处理器运行一个函数时,它并不总是从头到尾一次性运行所有函数。有时,当一个函数在等待其他事情发生(例如读取文件)时,操作系统会交错调用其他函数、协程或CPU内核上的其他程序。该图显示了一个为并发设计的程序如何可以在单核上运行,也可以在多核上运行。它还显示了并行运行时,与在单核上运行时相比,goroutine的更多段可以装入相同的时间帧(9个垂直段,如图所示)。

图分为两列,标记为并发和并行。并发列有一个高大的矩形,标记为CPU核心,分为不同颜色的堆叠段,表示不同的功能。Parallelism列有两个相似的高矩形,都标记为CPU核心,每个堆叠的部分表示不同的函数,除了它只显示goroutine1运行在左侧核心和goroutine2运行在右侧核心。

图中的左列,标记为“并发”,展示了围绕并发设计的程序如何通过运行goroutine1的一部分,然后运行另一个函数、goroutine或程序,然后运行goroutine2,然后再次运行goroutine1,以此在单个CPU内核上运行。对于用户来说,这看起来像是程序在同时运行所有函数或协程,即使它们实际上是一个接一个地在小的部分中运行。

图中右侧标记为“Parallelism”的列展示了同一个程序如何在具有两个CPU内核的处理器上并行运行。第一个CPU核心显示goroutine1与其他函数、goroutines或程序一起运行,而第二个CPU核心显示goroutine2与该核心上的其他函数或goroutines一起运行。有时goroutine1goroutine2同时运行,只是在不同的CPU内核上。

此图还展示了Go的另一个强大特性,可扩展性。当一个程序可以运行在任何设备上(从只有几个处理器内核的小型计算机到拥有几十个内核的大型服务器),并利用这些额外的资源时,它就是可扩展的。该图显示,通过使用goroutines,你的并发程序能够在单个CPU核上运行,但随着更多的CPU核的添加,更多的goroutines可以并行运行以加速程序。

要开始使用新的并发程序,请在你选择的位置创建一个multifunc目录。你可能已经为你的项目创建了一个目录,但在本教程中,你将创建一个名为projects的目录。你可以通过IDE或命令行创建projects目录。

如果你使用的是命令行,首先创建projects目录并导航到它:

mkdir projects
cd projects

projects目录中,使用mkdir命令创建程序的目录(multifunc),然后导航到它:

mkdir multifunc
cd multifunc

进入multifunc目录后,使用nano或你最喜欢的编辑器打开一个名为main.go的文件:

nano main.go

main.go文件中粘贴或输入以下代码以开始。

projects/multifunc/main.go

package main

import (
	"fmt"
)

func generateNumbers(total int) {
   
	for idx := 1; idx <= total; idx++ {
   
		fmt.Printf("Generating number %d\n", idx)
	}
}

func printNumbers() {
   
	for idx := 1; idx <= 3; idx++ {
   
		fmt.Printf("Printing number %d\n", idx)
	}
}

func main() {
   
	printNumbers()
	generateNumbers(3)
}

这个初始程序定义了两个函数,generateNumbersprintNumbers,然后在main函数中运行这些函数。generateNumbers函数以要“generate”的数字的数量作为参数,在本例中是1到3,然后将这些数字都打印到屏幕上。printNumbers函数还没有接受任何参数,但它也会打印出1到3的数字。

保存main.go文件后,使用go run运行它以查看输出:

go run main.go
OutputPrinting number 1
Printing number 2
Printing number 3
Generating number 1
Generating number 2
Generating number 3

你会看到这些函数一个接一个地运行,printNumbers首先运行,generateNumbers其次运行。

现在,想象一下printNumbersgenerateNumbers的运行时间都是三秒。当同步运行时,或者像上一个例子那样一个接一个地运行时,你的程序需要6秒才能运行。首先,printNumbers将运行三秒,然后generateNumbers将运行三秒。然而,在你的程序中,这两个函数是相互独立的,因为它们运行时不依赖于对方的数据。你可以利用这一点,通过使用goroutines并发运行函数来加速这个假设的程序。理论上,当两个函数同时运行时,程序的运行时间可以减少一半。如果printNumbersgenerateNumbers函数运行都需要3秒,并且都在同一时间开始,程序可能在3秒内完成。(不过,实

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HQL优化之数据倾斜

group by导致倾斜 前文提到过&#xff0c;Hive中未经优化的分组聚合&#xff0c;是通过一个MapReduce Job实现的。Map端负责读取数据&#xff0c;并按照分组字段分区&#xff0c;通过Shuffle&#xff0c;将数据发往Reduce端&#xff0c;各组数据在Reduce端完成最终的聚合运算。…

SpringCloud-高级篇(八)

&#xff08;1&#xff09;TCC模式 前面学了XA和AT模式&#xff0c;这两种模式最终都能实现一致性&#xff0c;和隔离性&#xff0c;XA是强一致&#xff0c;AT是最终一致&#xff0c;隔离性呢XA是在第一阶段不提交&#xff0c;基于事务本身的特性来完成隔离&#xff0c;AT则是…

MongoDB表的主键可以重复?!MongoDB的坑

MongoDB表的主键可以重复&#xff1f;&#xff01; 眼见为实&#xff1f; 碰到一个奇怪的现象&#xff0c; MongoDB的一个表居然有两个一样的_id值&#xff01; 再次提交时&#xff0c;是会报主键冲突的。那上图&#xff0c;为什么会有两个一样的_id呢&#xff1f; 将它们的…

【halcon深度学习】目标检测的数据准备过程中的一个库函数determine_dl_model_detection_param

determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议使用这一过程来优化训练和推断性能。 过程签名 determine_dl_model_detection…

10 新字符设备驱动文件

一、新字符设备驱动原理 因为 register_chrdev 和 unregister_chrdev 两个函数是老版本驱动文件&#xff0c;现在可以用新字符设备驱动 API 函数。 1. 分配和和释放设备号 使用 register_chrdev 函数注册字符设备的时候只需要给定一个主设备号即可&#xff0c;但是这样会带来两…

【面试】广告优化

a1&#xff1a;点击率公式是什么&#xff1f;点击率低的原因是什么&#xff1f; 点击率点击/曝光&#xff0c;点击率低的原因主要有两点&#xff1a;一是创意不吸引人&#xff1b;二是目标受众不准确/定向过宽不精确&#xff0c;广告曝光给了对产品不感兴趣用户 a2&#xff1a;…

数据库——关系数据的规范化:范式判断【知识点罗列+例题讲解】

知识点罗列&#xff1a; 各种范式之间的关系 1.第一范式1NF&#xff1a; 如果关系模式R中所有的属性都具有原子性&#xff0c;均是不可再分的&#xff08;一个属性不能再被分解成更小的数据单元&#xff09;&#xff0c;则称R属于第一范式&#xff0c;简称1NF&#xff0c;记作R…

linux常见错误

1.E45: ‘readonly‘ option is set (add ! to override) 首先使用以下命令从Vim编辑器中出来&#xff1a;:qa!(强制退出) 接下来&#xff0c;使用sudo vim filename和更高版本&#xff1a;:wq 2.Bash script – "/bin/bash^M: bad interpreter: No such file or direc…

yolov5单目测距+速度测量+目标跟踪

要在YOLOv5中添加测距和测速功能&#xff0c;您需要了解以下两个部分的原理&#xff1a; 单目测距算法 单目测距是使用单个摄像头来估计场景中物体的距离。常见的单目测距算法包括基于视差的方法&#xff08;如立体匹配&#xff09;和基于深度学习的方法&#xff08;如神经网…

安捷伦N9020A 是德keysight/N9020A

N9020A信号分析仪自动化和通讯接口&#xff1a; 符合 LXI、SCPI 和 IVI-COM USB 3.0、1000Base-T LAN、GPIB 编程与 PSA、8566/68 和 856x 的远程语言兼容性 通用 X 系列用户界面 / 开放式 Windows 7 操作系统&#xff08;标准&#xff09; 将现有的 MXA 从 Windows XP 迁移到…

CAN 五: CAN编程实践

1、CAN基本驱动步骤 (1)CAN参数初始化 工作模式、波特率等函数&#xff1a;HAL_CAN_Init (2)使能CAN时钟和初始化相关引脚 GPIO模式设为复用功能模式函数&#xff1a;HAL_CAN_MspInit(CAN的初始化回调函数) (3)设置过滤器 过滤器的配置函数&#xff1a;HAL_CAN_ConfigFil…

【linux】(ubuntu)下 QT 出现的问题

错误一&#xff1a;Make 运行QT程序以后出现这样的错误。 【解决方法】 我的ubuntu版本是18.04.4&#xff0c; 原因1&#xff1a;没有更换软件源 原因2&#xff1a;没安装相关 软件包 注意&#xff1a;这一步很有可能卡死这一步&#xff0c;所以如果一直卡在这并且进度…

黑马点评01

基础篇-07.Redis命令-数据结构介绍_哔哩哔哩_bilibili 1.NoSQL 非结构化数据库&#xff0c;和sql的区别在于没有数据库表之间的关系&#xff08;主键外键&#xff09;&#xff0c;一般的存储形式是JSON。每个json里面都存储了该记录的所有数据&#xff0c;所以有一定重复性。 …

总结一些vue3小知识2

1.el-tree-select和el-tree组件报错&#xff08;有的下拉选项选择不了&#xff0c;一点击就报错&#xff0c;但是有的却能选择&#xff0c;不会报错&#xff09; 原因:就如同v-for一样&#xff0c;需要添加key才不会出现渲染错误&#xff0c;而el-tree-select和el-tree组件需要…

MySQL数据库 DCL

目录 DCL概述 管理用户 权限控制 DCL概述 DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访 问权限。 管理用户 (1) 查询用户 select * from mysql.user; 查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localh…

计算机组成原理-指令系统CISC和RISC

文章目录 总览CISC和RISC 总览 CISC和RISC 存储程序就是用一个电路再加上存储部件构成 可访存指令不同 RISC更自由&#xff0c;因为很多函数没有固定&#xff0c;是自己写的 由于CISC各个指令执行时间不一样&#xff0c;要实现指令流水线比较困难 由于CISC可访存指令没有限制…

LVS负载均衡群集,熟悉LVS的工作模式,了解LVS的调度策略以及ipvsadm工具的命令格式

目录 一、什么是群集 群集的作用&#xff1a; 群集的目的是什么 根据群集所针对的目标差异&#xff0c;可分为三种类型 负载均衡群集&#xff08;LBC&#xff09;load balance cluster 高可用群集&#xff08;HAC&#xff09;high availability cluster 高性能运算群集&a…

【Docker】5. Dockerfile 构建和管理容器化应用程序

▒ 目录 ▒ &#x1f6eb; 导读开发环境 1️⃣ Dockerfile介绍 基本语法 指令 2️⃣ 实战&#xff1a;Python 的 Flask Web 代码 编译运行 发布到服务器 &#x1f6ec; 文章小结&#x1f4d6; 参考资料 &#x1f6eb; 导读 开发环境 版本号描述文章日期2023-12-15操作系统…

Dagger2基本使用2之子组件

一&#xff0c;基本使用&#xff0c;完成一个注入 1&#xff0c;创建作用域 //自定义作用域&#xff0c;作用域只是一个名称&#xff0c;随便起啥名字都可以&#xff0c;这里取一个全局单利的名字 Scope Documented Retention(RUNTIME) public interface GlobalSingleton { }…

LVS负载均衡器(DR模式)+nginx七层代理+tomcat多实例+php+mysql 实现负载均衡以及动静分离、数据库的调用!!!

目录 前言 一、nfs共享存储&#xff0c;为两个节点服务器提供静态网页共享 二、nginx作为lvs的后端节点服务器&#xff0c;完成lo:0网卡配置&#xff0c;以及内核参数设置&#xff0c;还有设置路由表 步骤一&#xff1a;先完成nfs共享存储挂载 步骤二&#xff1a;完成lo:0网…