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

引言

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 mainimport ("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.mzph.cn/news/227626.shtml

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

相关文章

mmpose 使用笔记

目录 自己整理的可以跑通的代码&#xff1a; 图片demo&#xff1a; 检测加关键点 自己整理的可以跑通的代码&#xff1a; 最强姿态模型 mmpose 使用实例-CSDN博客 图片demo&#xff1a; python demo/image_demo.py \tests/data/coco/000000000785.jpg \configs/body_2d_k…

AE-制作绚丽的图形通道

目录 1.新建合成命名为四边形 2.在合成中新建纯色层命名为tao 3.在纯色层上添加RG Trapcode –>Tao 效果&#xff0c;设置Segment参数 4. 在合成中添加摄像机 5.设置Tao Repeat Paths 相关参数&#xff0c;并调整摄像机的位置 6.设置Tao的 Material & Lighting 等…

skynet笔记

1、skynet.newservice和skynet.uniqueservice的区别 skynet.newservice&#xff1a; 当调用skynet.newservice时&#xff0c;它会每次都创建一个新的服务实例&#xff0c;即使之前已经存在相同类型的服务实例。这意味着可以同时启动多个相同类型的服务实例&#xff0c;它们之…

基于Springboot的高校教学评价系统的设计与实现(源码+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于Springboot的高校教…

【C++】std::bind与functional函数对象

functional 文章目录 functionalstd::bind使用示例 std::function类模板成员函数使用推导指引(C17 起) std::bind 原型&#xff1a; template< class R, class F, class... Args > constexpr /* 未指定 */ bind( F&& f, Args&&... args );函数模板 std…

如何通过TortoiseGit可视化工具查看Git管理的版本树和信息(工作树变更)内容

一、版本树 黑色直线&#xff1a;master分支和基于master分支拉取基础分支都在这条线上&#xff0c;是一条直线。 其他线条&#xff1a;新开分支一定会增加一条线&#xff0c;但不一定每一条线分别代表一个分支。 注&#xff1a;如果一直是一个人&#xff0c;在同一个本地分支…

(三)Java 基本数据类型

目录 一. 前言 二. 基本数据类型 2.1. char&#xff08;字符型&#xff09; 2.2. byte&#xff08;字节型&#xff09; 2.3. short&#xff08;短整型&#xff09; 2.4. int&#xff08;整型&#xff09; 2.5. long&#xff08;长整型&#xff09; 2.6. float&#xff…

powerbuilder游标的使⽤

在某些PowerBuilder应⽤程序的开发中,您可能根本⽤不到游标这样⼀个对象。因为在其它⼯具开发中很多需⽤游标实现的⼯作,在PowerBuilder中却已有DataWin-dow来代劳了。事实上,DataWindow不仅可以替代游标进⾏从后台数据库查询多条记录的复杂操作,⽽且还远不⽌这些。但是同DataW…

前端如何设置模板参数

1.背景&#xff1a; 最近接到一个需求&#xff0c;在一个类似chatGpt的聊天工具中&#xff0c;要在对话框中设置模板&#xff0c;后端提供了很多模板参数&#xff0c;然后要求将后端返回的特殊字符转成按钮&#xff0c;编辑完成后在相应的位置拼接成字符串。 2.效果&#xff1a…

C++ 类模板

目录 前言 类模板语法 类模板和函数模板的区别 类模板没有自动类型推导的使用方式 类模板在模板参数列表中可以有默认参数 类模板中成员函数创建时机 类模板对象做函数参数 指定传入的类型 参数模板化 整个类模板化 类模板与继承 类模板成员函数类外实现 类模板分…

在Spring Cloud中使用OpenFeign完成从一个微服务上传到另一个微服务中

跨服务上传文件&#xff0c;嘿嘿&#xff0c;来一篇实用性高的&#xff0c;本篇将主要完成在Feign中上传文件到另一个微服务中。步骤如下&#xff1a; 我们需要在服务提供者和服务消费者的项目中添加相应的依赖&#xff1a; 对于服务提供者的项目&#xff0c;你需要添加Sprin…

Redis设计与实现之集合及有序集

目录 一、集合 1、编码的选择 2、编码的切换 3、 字典编码的集合 4、集合命令的实现 5、 求交集算法 6、求并集算法 7、 求差集算法 二、有序集 1、编码的选择 2、编码的转换 3、ZIPLIST 编码的有序集 4、SKIPLIST 编码的有序集 三、如何添加元素到集合或有序集中…

Next.js 学习笔记(二)——项目结构

Next.js 项目结构 此页面提供了 Next.js 项目的文件和文件夹结构的概述。它涵盖了 app 和 pages 目录中的顶级文件和文件夹、配置文件以及路由约定。 顶级文件夹 文件夹名描述appApp RouterpagesPages Routerpublic待服务的静态资源src可选的应用程序源文件夹 顶级文件 文…

万兆网络之屏蔽线序接法(中)

在介绍优质网线选购之前&#xff0c;先简单介绍一下水晶头 1毛钱一颗跟1元一颗的水晶头&#xff0c;往往是金手指厚度差别&#xff0c;你可以想象压制的时候可能会有什么情况 另外&#xff0c;一些3元一颗的镀金水晶头会有15U、30U之类的是电镀厚度单位&#xff0c;数值越大镀…

React Native面试题总结

1,简单介绍下React Native,以及和React.js的区别 React Native是一个JavaScript框架,由Facebook开发,以满足日益增长的移动应用开发的需求。它是开源的,基于JavaScript的。它被设计为用可重复使用的组件构建本地移动应用程序。它使用了大量的ReactJS组件,但在不同的设备…

文档安全加固:零容忍盗窃,如何有效预防重要信息外泄

文档安全保护不仅需要从源头着手&#xff0c;杜绝文档在使用和传播过程中产生的泄密风险&#xff0c;同时还需要对文档内容本身进行有效的保护。为了防范通过拷贝、截屏、拍照等手段盗窃重要文档内容信息的风险&#xff0c;迅软DSE加密软件提供了文档加密保护功能&#xff0c;能…

10 新字符设备驱动文件

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

如何计算2的n次方

今天在写代码的时候&#xff0c;遇到了纹饰评分的计算&#xff0c;纹饰的等级和评分的关系为&#xff1a; 1级纹饰&#xff1a;202级纹饰&#xff1a;403级纹饰&#xff1a;80 得出纹饰等级grade和纹饰评分score的关系&#xff1a;score (2 ^ grade) * 10&#xff0c;所以就…

git 不小心操作 reset current branch to here后,怎么还原

可以通过reflog来进行恢复&#xff0c;前提是丢失的分支或commit信息没有被git gc清除 一般情况下&#xff0c;gc对那些无用的object会保留很长时间后才清除的 可以使用git reflog show或git log -g命令来看到所有的操作日志 恢复的过程很简单&#xff1a; 通过git log -g命…

信息安全和网络安全的区别

信息安全与网络安全都属于安全领域&#xff0c;但它们的范围和重点不同。 信息安全主要关注数据的保护&#xff0c;包括对敏感数据进行加密、防止数据丢失或泄露等措施。信息安全通常与数据存储、传输和处理相关。 而网络安全更侧重于保护计算机系统和网络免受攻击、病毒、蠕…