我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Go并发编程的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Go并发编程的示例分析

这篇文章给大家分享的是有关Go并发编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

一、goroutine

定义

  • 给函数前加上go即可

  • 不需要在定义是区分是否是异步函数

  • 调度器在合适的点进行切换,这个点是有很多的,这里只是参考,不保证切换,不能保证在其它地方不会被切换。IO操作、channel、等待锁、函数调用、runtime.Gosched()等。。。

  • 使用race来检测数据访问冲突

先看案例知道goroutine怎么用

先来看一个案例

Go并发编程的示例分析

这个案例就是一个简单并发执行的代码,在go里边也就是一个关键字go即可。

那么来看一下这段代码会输出什么

Go并发编程的示例分析

从上图可以看到这行代码什么都没有输出,直接就退出了,那这到底是什么情况呢?

直接退出的原因,就是因为我们代码中的main和fmt打印是并发执行的,fmt还没来的急打印数据,外层的循环就已经循环结束了,然后就直接退出了。

在go语言中呢!假设一个main函数退出后,会直接杀死所有的goroutine,所以就造成的现象是,goroutine还没来的急打印数据就被退掉了。

那么你是不是会想,要怎么样才能看到打印的数据呢?其实也很简单,就是让main函数执行完成之后不要着急的退出,给一点等待的时间。看案例

Go并发编程的示例分析

这次希望出现的结果就显示出来了。

在本案例中开的goroutine是10个,那么改为1000会怎么样呢?

结果显示还是正常显示,就类似与有1000个人在同时打印东西。

那么设置10跟1000有什么关系吗?

对操作系统熟悉的应该都知道,开10个线程没有问题,开100个线程也没什么大的问题,但是已经差不多了。

一般系统开几十个线程就可以了,那么如果要1000个人同时做一件事情就不能用线程来解决了,需要通过异步方式。

但是在go语言中呢!直接使用go关键字即可,就可以并发执行。

接下来就聊聊为什么go就可以同时1000进行打印。

是什么

先来看看协程和线程的区别。

协程你可以理解为轻量级的线程非抢占式多任务处理,由协程主动交出控制权

线程大家应该都知道是可以被操作系统在任何时候进行切换,所以说线程就是抢占式多任务处理,线程是没有控制权,哪怕是一个语句执行到一半都会被操作系统切掉,然后转到其它线程去操作。

那么反之对于协程来说,什么时候交出控制权,什么时候不交出控制权是由协程内部主动决定的,正是因为这种非抢占式,所以被称之为轻量级。

并且多个协程是可以在一个或多个线程上运行的

二、channel

在第一节中了解到,在go中是可以开非常多的goroutine的,那么goroutine之间的双向通道就是channel

Go并发编程的示例分析

基础用法

Go并发编程的示例分析

从上图案例中可以看到可以直接使用make函数来进行创建channel。

第七行、第八行就是往channel中发送数据。

那么这个案例可以运行吗?来试一下

Go并发编程的示例分析

可以看到此时已经报错了,错误的意思就是在往channel发送1的时候会发生死锁。

然后在回到之前的那副图。

Go并发编程的示例分析

在上文我们已经说了,channel是goroutine与goroutine之间的一个交互。

但是此时的案例中缺只有一个goroutine,所以还需要一个另一个goroutine来接收它。

现在你应该了解到如何开启一个goroutine了。

Go并发编程的示例分析

在上图中我们新开启了另一个goroutine,然后用了一个死循环来接受channel发送的值,并将其打印出来。

但是你会发现我们往channel中发送了俩个数据,此时的打印结果却只有一条数据。但总比我们刚开始的好多了,对吧!

那么为什么会发生这样的情况呢?

可以理理代码的执行流程,先往channel发送了一个1,然后循环获取到第一个值并打印。

再往channel发送数据2,但还没来得及打印就直接退出了,这也就造成了只显示了数据1而没有显示数据2的现象。

这个问题通过咔咔的描述你应该已经知道怎么解决了。

那就是给函数channelDome加一个延迟退出的时间即可。

Go并发编程的示例分析

将channel作为参数传递

在上文中可以看到go后边跟的是一个闭包函数,在这个闭包中使用的c就是使用的外层的c。

那么将这个c使用参数传递可否呢?答案是肯定可以的。

Go并发编程的示例分析

当然也可以传递其它的参数

Go并发编程的示例分析

通过上图可以看到不仅仅传递了channel还传递了id参数,同时还可以将代码直接优化为圈住的部分,也就是直接从channel取值。

创建多个channel

Go并发编程的示例分析

从上图可以看到每个人都有自己的channel,然后进行分发,分发之后每个人都会收到自己的接收到的值并打印出来。

同样你可以看到我们在26行处还新加了一个for循环给channle里边发送数据。

Go并发编程的示例分析

从运行结果中你会发现打印的顺序是混乱的,例如receive i 和receve I这俩个值。

此时你会不会有疑问,我们在往channel中发送数据时是按照顺序发送的啊!那么接收时肯定也是按照顺序接收的。

既然非常确定发送数据是按照顺序的,那么问题就只能出现在Printf这里。

因为Printf是存在IO的,goroutine进行调度,那么此时的Printf是乱序的,但是都会将收到的值一一打印出来。

将channel作为返回值

前几节的案例都是通过创建好的channle然后作为参数传递进去的。

那么本节将会把channel作为一个返回值给返回出去。

Go并发编程的示例分析

源码

package mainimport ("fmt""time")func createWorker(id int) chan int {c := make(chan int)go func() {for {fmt.Printf("Worker %d receive %c\n", id, <-c)}}()return c}func channelDemo() {var channels [10]chan intfor i := 0; i < 10; i++ {channels[i] = createWorker(i)}for i := 0; i < 10; i++ {channels[i] <- 'a' + i}time.Sleep(time.Millisecond)}func main() {channelDemo()}

从这里你可以看到我们将worker函数改为了createWorker函数,因为在这个函数里边就是直接创建channel。

接着通过一个协程将channel接收到的值进行打印。

在把channel进行返回出去。

来看一下运行结果

Go并发编程的示例分析

通过运行结果可以得知我们的代码编写还是对的,但是此时返回的channel你可以非常直观的看到怎么用

但如果代码数量多的时候,你根本不清楚这个channel怎么用,所有这段代码还需要简单的修饰一下。

那么就需要做的事情的是告诉外面用的人应该怎么用。

Go并发编程的示例分析

通过上述代码可以得知,是往channel中发送数据的,那么在createWorker方法的返回的channel要标记一下

Go并发编程的示例分析

所以说现在的代码就变成这个样子,我们直接给createWorker方法的返回值channel标记好方向。作用是送数据的。

那么在打印的时候就是收据,这样看起来就非常直观了。

当修改完上面俩步之后你会发现createWorker调用是报错了,Cannot use 'createWorker(i)' (type chan<- int) as type chan int看到错误就应该知道是俩边类型不对等。

Go并发编程的示例分析

修改完之后你就会发现编译正确了,没有报错信息了。

运行结果也是ok的。

Go并发编程的示例分析

本小节源码

package mainimport ("fmt""time")func createWorker(id int) chan<- int {c := make(chan int)go func() {for {fmt.Printf("Worker %d receive %c\n", id, <-c)}}()return c}func channelDemo() {var channels [10]chan<- intfor i := 0; i < 10; i++ {channels[i] = createWorker(i)}for i := 0; i < 10; i++ {channels[i] <- 'a' + i}time.Sleep(time.Millisecond)}func main() {channelDemo()}

buffer channel

学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么?

Go并发编程的示例分析

没错,会发生报错,因为在文章开头咔咔就讲过了,给一个channel发送数据,就需要开启另一个协程来收数据。

虽然协程我们说是轻量级的,但是如果发送了数据之后,就需要切换协程来进行收数据就非常的耗费资源。

那么就是本节给大家讲解的东西。

Go并发编程的示例分析

创建了可以有3个缓冲区的channel,然后往channel发送3个数据。

同时运行结果也可以得知没有在发生deadlock

给你一个问题,如果往缓冲区在发送一个数据4会发生什么呢?

Go并发编程的示例分析

聪明的你,肯定就想到结果了,没错,报了deadlock

接着我们就使用之前的worker,来接受channel的数据。

Go并发编程的示例分析

但是你会发现运行结果还是没有打印出送进去的1,2,3,4。

这个问题现在也已经说了好几次了,你可以试着问一下你自己,这种情况你应该怎么解决。

Go并发编程的示例分析

也就是加一个延迟时间即可,这里顺便给大家说明一下,之前的那个案例打印的是字母,所有格式化用的%c,现在打印的是数字,所以改为了%d,一点小小的改动。

这种方式建立channel对性能的提升是有一定的作用的。

到现在你有没有发现一个问题,那就是在发送channel时不知道什么时候发完了。

接下来就来看这个问题。

channel关闭

借用上个案例的代码来继续进行说明。

Go并发编程的示例分析
跟上节代码不一致的是,我们在结尾处添加了close,close需要注意的是在发送方进行关闭的。

你会看到运行结果并不如意,你会发现虽然收到了1,2,3,4。

但是下面还接收到了非常多的0,只是截图只截到了一条数据而已。

虽然发送方将channel给close掉了,但是接受放也就是worker还是会收到数据的,不是说channel给close后就收不到数据了。

但是当发送方将channle设置为close之后,收到的数据就都是0,也就是收到的是worker方法传递的c chan int这个参数0的值。

现在我们的channel是一个int类型,收到的是0。那么如果是一个string类型,收到的就是一个空字符串。

这个会收多久呢?也就是咱们设置的一毫秒的时间。

如果让你改这段程序你有没有思路呢?如果没有思路就跟这咔咔的节奏一起摇摆。

Go并发编程的示例分析

在函数worker中,使用俩个值来进行接收,n就是传递过来的channel c。ok就是判断这个值是否存在。

可以看到运行结果,就不会在出现接收到0的数据了。

除了这种写法还有一种更简单的方式。

Go并发编程的示例分析

感谢各位的阅读!关于“Go并发编程的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Go并发编程的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Go并发编程的示例分析

这篇文章给大家分享的是有关Go并发编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、goroutine定义给函数前加上go即可不需要在定义是区分是否是异步函数调度器在合适的点进行切换,这个点是有很多
2023-06-20

SingleFlight模式的Go并发编程实例分析

这篇文章主要介绍了SingleFlight模式的Go并发编程实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SingleFlight模式的Go并发编程实例分析文章都会有所收获,下面我们一起来看看吧。在go
2023-06-30

Java并发编程之线程池的示例分析

这篇文章将为大家详细讲解有关Java并发编程之线程池的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是线程池是一种基于池化思想管理线程的工具。池化技术:池化技术简单点来说,就是提前保存大量的资
2023-06-20

Java面试题之并发编程的示例分析

小编给大家分享一下Java面试题之并发编程的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!面试题1:说一下你对ReentrantLock的理解?ReentrantLock是JDK1.5引入的,它拥有与synchro
2023-06-20

Java并发编程之ConcurrentLinkedQueue源码的示例分析

这篇文章给大家分享的是有关Java并发编程之ConcurrentLinkedQueue源码的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、ConcurrentLinkedQueue介绍并编程中,一般需
2023-06-15

JUC并发编程中进程与线程的示例分析

这篇文章将为大家详细讲解有关JUC并发编程中进程与线程的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。进程与线程进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,
2023-06-29

Go中同时使用并发和并行编程的案例分析

go 同时支持并发 (通过 goroutine) 和并行 (通过协程) 以提升效率。goroutine 允许同时执行独立任务,而通道则实现 goroutine 之间的通信。该示例演示了如何使用并发和并行计算质数,提高计算效率。使用 Go 进
Go中同时使用并发和并行编程的案例分析
2024-05-12

Java并发编程之Fork/Join框架的示例分析

这篇文章主要介绍了Java并发编程之Fork/Join框架的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、Fork/Join框架的理解ForkJoinTask类属
2023-06-15

Java并发编程之关键字volatile的示例分析

这篇文章给大家分享的是有关Java并发编程之关键字volatile的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、作用被 volatile 修饰的变量1.保证了不同线程对该变量操作的内存可见性2.禁止
2023-06-15

Go并发编程之死锁与活锁的案例分析

死锁就是在并发程序中,两个或多个线程彼此等待对方完成操作,从而导致它们都被阻塞,并无限期地等待对方完成;活锁就是程序一直在运行,但是无法取得进展。本文将从一些案例出发,分析一下它们,希望对大家有所帮助
2023-05-18

Java并发编程之同步容器与并发容器的示例分析

这篇文章主要为大家展示了“Java并发编程之同步容器与并发容器的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程之同步容器与并发容器的示例分析”这篇文章吧。一、同步容器 1
2023-06-15

Java并发编程中Semaphore计数信号量的示例分析

这篇文章主要为大家展示了“Java并发编程中Semaphore计数信号量的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程中Semaphore计数信号量的示例分析”这篇文章
2023-05-31

Java中多线程与并发的示例分析

这篇文章主要介绍Java中多线程与并发的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、进程与线程进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。线程:是进程的一个执行路径,一个
2023-06-15

编程语言之高并发系统中限流的示例分析

这篇文章主要介绍了编程语言之高并发系统中限流的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。本文结合作者的
2023-05-30

Java并发中守护线程的示例分析

今天就跟大家聊聊有关Java并发中守护线程的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemo
2023-06-17

golang中并发和并行的示例分析

这篇文章主要介绍了golang中并发和并行的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是golanggolang 是Google开发的一种静态强类型、编译型、
2023-06-15

Java之JMM高并发编程实例分析

这篇文章主要介绍“Java之JMM高并发编程实例分析”,在日常操作中,相信很多人在Java之JMM高并发编程实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java之JMM高并发编程实例分析”的疑惑有所
2023-07-02

udp编程的示例分析

小编给大家分享一下udp编程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!什么是UDP?UDP是User Datagram Protocol(用户数据报
2023-06-27

java高并发中并发级别的示例分析

这篇文章给大家分享的是有关java高并发中并发级别的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。阻塞一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。当我们使用synchronized
2023-06-25

Go语言中并发goroutine底层原理的示例分析

小编给大家分享一下Go语言中并发goroutine底层原理的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、基本概念①并发、并行区分1.概念并发:同一时间段内一个对象执行多个任务,充分利用时间并行:同一时刻,多个
2023-06-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录