越来越多的人开始注意到golang的高效性,于是很公司开始使用golang去做业务。这方面七牛成为了第一个吃螃蟹的公司。听说golang的高效,就是因为在并发时使用了比线程还要小的协程。至于为什么会可以达到这个效果,作为初学者的我还是不懂
一:什么是并发
简单来讲,并发就是让多个任务可以同时去执行,而不是过程式的必须从前往后来,并且一次只能执行一个任务。当前比较主流的并发实现模式有如下几种
1.多进程。操作系统层面的模式
2.多线程。大部分在操作系统上,也是使用最多的
3.基于回调的非阻塞/异步IO
4.协程。是一种用户态线程,不需要操作系统来进行抢占式调用,但又在真正的实现中寄存于线程中,系统开销极小。非常高效的实现任务的并发性
二:协程goroutine
goroutine是Go语言中的轻量级线程实现,由Go运行时管理。这些书面的说起来也难以理解。下面我们看一个例子-试下一个Add函数,把两个参数相加,并把结果打印如下
func Add(x, y int) int{
z := x + y
fmt.Println(z)
return z
}
那么在golang中我们怎么去让这个函数并发的去执行呢?go关键字出现了,他是语言本身最重要的关键字,在函数前面添加go就是让函数并发执行!下面我们看看效果吧!
package main
import "fmt"
func main(){
for i:=0;i<10;i++{
go Add(i,i)
}
}
按照常理这个时候我们就会说,“看,接着我就要打印10次了!”跑一遍试试。
怎么什么也没有呢?难道没有执行吗?到底是什么原因产生了这种令人难以捉摸的现象呢?就是因为在调用Add()函数的时候前面的那个关键字起作用了,当不加关键字的时候程序都是在main这个主函数中执行,然后按照顺序来执行,所以就会打印十次。但是go 的出现让它成为了另一个线程与主线程去并发执行了。go的执行机制是从main开始,它又启动了10个协程序。当它执行完返回时,协程还没有来得及执行。所以就什么也没打印了!现在懂了吧。是不是很有趣呢!既然知道了,我们应该怎么去保证等10个协程执行完呢?
解决方法一(共享内存)也就是其他语言中普遍解决的原理:直接上代码
package main
import (
"fmt"
"runtime"
"sync"
)
/***定义一个计数器,记录协程运行完成的个数*/
var counter int = 0
func Add(x, y int) int {
z := x + y
return z
}
/****记录协程执行个数的方法,每完成一个计数器就添加1*/
func Count(lock *sync.Mutex, x int, y int) {
lock.Lock()
counter++
fmt.Println(Add(x, y))
lock.Unlock()
}
func main() {
lock := &sync.Mutex{}
for i := 0; i < 10; i++ {
go Count(lock, i, i)
}
//让主程序进行等待,直到10个协程序都完成后才退出主程序
for {
lock.Lock()
c := counter
lock.Unlock()
runtime.Gosched()
if c >= 10 {
break
}
}
}
该例子中我们用到了一个全局变量counter计数器。同时还需要在协程执行方法时候进行锁定不让其他协程序执行!这样就保证了一个协程执行一次计数器就增加一。而在主程序中一直去变量计数器,直到达到10(也就是10个协程都执行完毕)退出。这样就能得到我们想要的结果了!
结果我们是得到了?但是这样真的好吗?是不是代码显得很浮肿?明明就是一个简单的东西还得写这么多代码?于是go就结束了这种笨重的方式。使用到了并发的另一种方式---协程间的通信(channel)
并发的通信方式channel
channel是进程内的通信方式,因此通过channel传递对象的过程和调用函数时的参数行为要一致
基本语法
//1.声明格式
var chanName chan ElementType
//2.也可以声明一个map形式
var m map[string] chan bool
//3.构造一个channel
ch:=make(chan int)
//4.将数据写入到channel
ch<-value
//5.读取数据
value:=<-ch
通过上面的图我们可以知道channel的大致流程,但在这里值得注意的就是,在写入和读的时候他们是阻塞的,也就是保证了只有一个线程进行读写操作,这样是不是不用进行繁琐的同步锁的过程了呢。说了这么多.在来看看例子.
package main
import (
"fmt"
"strconv"
//"time"
)
func Count(ch chan int) {
ch <- 345
fmt.Println("Counting")
}
func main() {
chs := make([]chan int, 10)
for i := 0; i < 10; i++ {
/**这里在创建的时候,默认是没有缓存的,所以若要想Count()函数里都印出来的话,需要将主线程停一段时间*/
chs[i] = make(chan int)
go Count(chs[i])
}
for _, ch := range chs {
value := <-ch
fmt.Println("value:", value)
}
//time.Sleep(1 * 1e9)
}
结果如下:
分析:看见这样的结果我们会觉得很奇怪?为什么读取到了10个值,但是却只打印了一个counting.不是10个都写进去了么?为什么只打印出来一个呢?想了很久?也试了很久最后得出结论-10个协程在写完的时候,主程序也在循环进行读的操作,当协程序写完数据还没执行到打印语句的时候,结果主线程已经读完了!这样就导致了只打印一次了?个人认为一次只是偶然,可以是几次!解决办法想到了三种:
1.就是我注释掉的,让主线程进行休眠一段时间等待
2.将第10行和第11行代码交换位置,先打印然后去写
3.在19行代码修改为
//后面添加1后,设置了缓存,等所有的协程都写完后,主线程才开始进行读操作
chs[i] = make(chan int,1)
对于第三种解释还是不太清楚。注释得也不纤细,希望大家自行验证!
- 大小: 12.5 KB
- 大小: 6.4 KB
- 大小: 13.3 KB
- 大小: 16.6 KB
分享到:
相关推荐
golang并发编程实战,channel原理实现过程,最佳实践,goroutine原理和go并发的实战,从实际出发展开对go并发编程的说明和示例,充分说明go语言再并发编程的优势
解决Golang并发性练习
本书首先介绍了Go语言的优秀特性、安装设置方法、工程结构、标准命令和工具、语法基础、数据类型以及流程控制方法,接着阐述了与多进程编程和多线程编程有关的知识,然后重点介绍了goroutine、channel以及Go提供的...
主要介绍了golang并发编程的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Go语言学习笔记-(详细书签)+Go并发编程实战[2015.1],都是比较新的资料,提供给大家学习,后期还有我写的示例程序,共同学习共同进步
并发编程模式介绍,golang自己提供的并发编程技巧和常用模式
go 并发编程实战 ,go 并发编程实战 mobi kindle 实测,放心下载
实现实现逻辑如下://LimitRate 限速type LimitRate struct {func (l *LimitRate) Limit() bool {
采用3D WebGL技术实现可视化预览。该工具旨在让开发者更好的了解Go并发。
建议学习实践: ...1. 要坚持实践高性能大并发编程的实践 2. Erlang基础->OTP高并发编程实践PDF->Elixir 3. 认真实践本书中的知识点, 动手练习, 高并发软件实时大容量的服务器开发可打败C++的大团队开发
goderive goderive派生了您不想维护的普通golang函数,并使它们保持最新状态。 它通过解析未实现的函数的go代码来执行此操作,然后生成这些函数goderive goderive派生不需要维护的普通golang函数并使它们保持最新...
介绍Go并发编程;深入理解Go并发模型;探讨Go并发编程范式;处理数据竞争等问题;学习Go并发编程范例;
go语言并发编程英文版。两百多页详细介绍了go语言并发编程模型和用法
本文档主要针对golang中的分享Go语言编程知识,探究Go语言并发编程原理等相关技术方面的优化讲解,方便开发人员学习提升相关方面的技能
2-1 并发编程启蒙 2-2 并发编程--协程 2-3 Golang协程基本示例 第3章 Go的协程 3-1 Golang协程特性实践 3-2 golang select多队列选择器 3-3 selete等待机制 第4章 示例环境搭建 4-1 快速构建一个示例网站(上) 4-2 ...
图灵原创——《GO并发编程实战》第二版。此书重点描述多进程和多线程编程相关的知识,此书基于go 1.8版本全面更新,结合实际代码例子,更深入秒回Go运行时系统内部原理,本文档附带书中go源码。对于Go语言编程感兴趣...
探探 Gopher China 2019 北京会场 Go 并发编程实践详细完整内容
《Go语言编程》高清完整版电子书 Go 1.5 源码剖析 (书签版) Go Web 编程 go程序设计语言 Go并发编程实战[2015.1] golang中文手册 GO 命令教程 - v1.0
戈德利夫 goderive派生出您不想维护的普通 golang 函数,并使它们保持最新状态。 它通过解析未实现的函数的 go 代码来完成此操作,然后通过从输入参数类型派生它们的实现来为您生成这些函数。例子在下面的代码中, ...