越来越多的人开始注意到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
分享到:
相关推荐
本书首先介绍了Go语言的优秀特性、安装设置方法、工程结构、标准命令和工具、语法基础、数据类型以及流程控制方法,接着阐述了与多进程编程和多线程编程有关的知识,然后重点介绍了goroutine、channel以及Go提供的...
### Golang并发编程实战 #### 一、Go语言并发编程概览 Go语言因其简洁的语法、高效的性能以及内置的并发支持,在后端开发领域备受青睐。本文将深入探讨Go语言中的并发编程技术,包括通道(channel)的工作原理、...
本文将深入探讨如何解决 Golang 并发性问题,并通过实际的练习来提升对并发编程的理解。 首先,Goroutines 是 Go 语言中的轻量级线程,它们比传统的操作系统线程更高效、更易于管理。创建一个 Goroutine 只需在函数...
"Go并发编程实战[2015.1]"是另一个重点,并发编程是Go语言的一大特色,它通过goroutines(轻量级线程)和channels实现,使得编写高效的多任务程序变得简单。这本书将教你如何利用这些特性构建高性能的并发应用,涵盖...
本文将探讨Go语言中的并发编程实现,包括goroutine的创建、channel的使用、以及并发控制结构sync.Mutex和sync.RWMutex的运用。 ### Goroutine的创建和运行 Go语言的并发核心是goroutine,它是Go语言运行时的一个轻...
3. **并发支持**:Go语言内置了并发编程的支持,通过Goroutines和Channels,可以轻松地实现并发。 4. **内存管理**:Go语言拥有自动垃圾回收机制,简化了内存管理。 5. **静态类型**:Go是一种静态类型语言,这有助...
从基础的数据类型、变量声明到复杂的并发编程模式,每个部分都包含了具体的实例进行解释和示范,使初学者能够快速掌握Go的基本用法及其强大的并行处理能力。此外,还包括了对自定义结构体及方法的设计、外部包的管理...
Go-Golang编程语言以其高效的并发模型闻名,它利用了CSP(Communicating Sequential Processes)的概念,通过goroutines和channels来实现。在这个标题为“Go-Golang编程语言的并发性跟踪和可视化工具”的主题中,...
通过本教程的学习,你可以掌握Go语言的基本语法、并发编程技巧,并了解如何使用Go进行实际项目开发。配合jb51.net上的资源,你可以找到更多的实践案例和进阶内容,进一步提升你的Go语言编程能力。
在这个"Go并发编程实践V2"的课程中,我们将深入探讨Go语言中的并发编程,并结合源代码来理解其工作原理。 并发编程是现代软件开发中的一个重要概念,它允许程序同时执行多个任务,从而提高系统的效率和响应性。Go...
3. **并发支持**:Go语言内置了并发编程的支持,通过Goroutines和Channels,可以轻松地实现并发。 4. **内存管理**:Go语言拥有自动垃圾回收机制,简化了内存管理。 5. **静态类型**:Go是一种静态类型语言,这有助...
通过这个并发聊天室项目,开发者不仅可以深化对Golang并发特性的理解,还能实际操作网络编程,体验到Go语言在处理高并发场景下的强大能力。此外,项目的实现过程也是对Golang基础语法和高级特性运用的综合训练,对...
3. **并发支持**:Go语言内置了并发编程的支持,通过Goroutines和Channels,可以轻松地实现并发。 4. **内存管理**:Go语言拥有自动垃圾回收机制,简化了内存管理。 5. **静态类型**:Go是一种静态类型语言,这有助...
在IT领域,编程语言Go(Golang)以其高效并发特性被广泛用于网络爬虫的开发。本主题聚焦于“golang语言爬虫并发版爬虫源码”,...通过学习和实践,你不仅可以掌握Go语言的并发编程,还能了解到网络爬虫设计的诸多细节。
go 并发编程实战 ,go 并发编程实战 mobi kindle 实测,放心下载
实现实现逻辑如下://LimitRate 限速type LimitRate struct {func (l *LimitRate) Limit() bool {
《Golang Web编程》英文版是一本专门针对使用Go语言进行Web开发的图书,适合对Go语言有一定了解并希望深入Web开发的读者。Go语言,由Google开发,以其简洁的语法、高效的性能以及内置的并发支持,近年来在Web开发...
其并发模型基于“goroutines”和“channels”,使得编写高效并发程序变得相对简单,这也是它适合构建压力测试工具的原因之一。 压力测试工具的主要目的是模拟大量用户同时访问服务,以检测系统的性能瓶颈和稳定性。...
在Go语言中,并发编程是其核心特性之一,也是实现高性能服务的关键技术。下面将详细讨论这本书中涉及的重要知识点。 1. **Goroutines与Channels**: - Goroutines是Go语言轻量级线程的实现,它们比传统的线程更...