`
daihongtao110121
  • 浏览: 15702 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

golang之并发编程

 
阅读更多
       越来越多的人开始注意到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
0
0
分享到:
评论

相关推荐

    Go并发编程实战+第2版_Lite.pdf_golang_

    本书首先介绍了Go语言的优秀特性、安装设置方法、工程结构、标准命令和工具、语法基础、数据类型以及流程控制方法,接着阐述了与多进程编程和多线程编程有关的知识,然后重点介绍了goroutine、channel以及Go提供的...

    golang并发编程实战

    ### Golang并发编程实战 #### 一、Go语言并发编程概览 Go语言因其简洁的语法、高效的性能以及内置的并发支持,在后端开发领域备受青睐。本文将深入探讨Go语言中的并发编程技术,包括通道(channel)的工作原理、...

    Go-解决Golang并发性练习

    本文将深入探讨如何解决 Golang 并发性问题,并通过实际的练习来提升对并发编程的理解。 首先,Goroutines 是 Go 语言中的轻量级线程,它们比传统的操作系统线程更高效、更易于管理。创建一个 Goroutine 只需在函数...

    GoLang学习资源_学习笔记和并发编程实战

    "Go并发编程实战[2015.1]"是另一个重点,并发编程是Go语言的一大特色,它通过goroutines(轻量级线程)和channels实现,使得编写高效的多任务程序变得简单。这本书将教你如何利用这些特性构建高性能的并发应用,涵盖...

    golang并发编程的实现

    本文将探讨Go语言中的并发编程实现,包括goroutine的创建、channel的使用、以及并发控制结构sync.Mutex和sync.RWMutex的运用。 ### Goroutine的创建和运行 Go语言的并发核心是goroutine,它是Go语言运行时的一个轻...

    探索Golang并发安全的奥秘:安全并发编程的艺术

    3. **并发支持**:Go语言内置了并发编程的支持,通过Goroutines和Channels,可以轻松地实现并发。 4. **内存管理**:Go语言拥有自动垃圾回收机制,简化了内存管理。 5. **静态类型**:Go是一种静态类型语言,这有助...

    Golang基础与并发编程示例详解

    从基础的数据类型、变量声明到复杂的并发编程模式,每个部分都包含了具体的实例进行解释和示范,使初学者能够快速掌握Go的基本用法及其强大的并行处理能力。此外,还包括了对自定义结构体及方法的设计、外部包的管理...

    Go-Golang编程语言的并发性跟踪和可视化工具

    Go-Golang编程语言以其高效的并发模型闻名,它利用了CSP(Communicating Sequential Processes)的概念,通过goroutines和channels来实现。在这个标题为“Go-Golang编程语言的并发性跟踪和可视化工具”的主题中,...

    golang 语言编程

    通过本教程的学习,你可以掌握Go语言的基本语法、并发编程技巧,并了解如何使用Go进行实际项目开发。配合jb51.net上的资源,你可以找到更多的实践案例和进阶内容,进一步提升你的Go语言编程能力。

    go并发编程实践V2+源代码

    在这个"Go并发编程实践V2"的课程中,我们将深入探讨Go语言中的并发编程,并结合源代码来理解其工作原理。 并发编程是现代软件开发中的一个重要概念,它允许程序同时执行多个任务,从而提高系统的效率和响应性。Go...

    Golang协程与Goroutine:并发编程的双生子

    3. **并发支持**:Go语言内置了并发编程的支持,通过Goroutines和Channels,可以轻松地实现并发。 4. **内存管理**:Go语言拥有自动垃圾回收机制,简化了内存管理。 5. **静态类型**:Go是一种静态类型语言,这有助...

    Golang实现并发聊天室

    通过这个并发聊天室项目,开发者不仅可以深化对Golang并发特性的理解,还能实际操作网络编程,体验到Go语言在处理高并发场景下的强大能力。此外,项目的实现过程也是对Golang基础语法和高级特性运用的综合训练,对...

    Golang竞态检测器:并发编程的安全网

    3. **并发支持**:Go语言内置了并发编程的支持,通过Goroutines和Channels,可以轻松地实现并发。 4. **内存管理**:Go语言拥有自动垃圾回收机制,简化了内存管理。 5. **静态类型**:Go是一种静态类型语言,这有助...

    golang语言爬虫 并发版爬虫源码

    在IT领域,编程语言Go(Golang)以其高效并发特性被广泛用于网络爬虫的开发。本主题聚焦于“golang语言爬虫并发版爬虫源码”,...通过学习和实践,你不仅可以掌握Go语言的并发编程,还能了解到网络爬虫设计的诸多细节。

    go 并发编程实战 mobi

    go 并发编程实战 ,go 并发编程实战 mobi kindle 实测,放心下载

    ghostwwl#note#golang并发编程的两种限速方法1

    实现实现逻辑如下://LimitRate 限速type LimitRate struct {func (l *LimitRate) Limit() bool {

    golang web编程英文版

    《Golang Web编程》英文版是一本专门针对使用Go语言进行Web开发的图书,适合对Go语言有一定了解并希望深入Web开发的读者。Go语言,由Google开发,以其简洁的语法、高效的性能以及内置的并发支持,近年来在Web开发...

    Go-golang编写的http压力测试工具支持不同类型请求并发支持请求权重

    其并发模型基于“goroutines”和“channels”,使得编写高效并发程序变得相对简单,这也是它适合构建压力测试工具的原因之一。 压力测试工具的主要目的是模拟大量用户同时访问服务,以检测系统的性能瓶颈和稳定性。...

    go 并发编程实战-郝林

    在Go语言中,并发编程是其核心特性之一,也是实现高性能服务的关键技术。下面将详细讨论这本书中涉及的重要知识点。 1. **Goroutines与Channels**: - Goroutines是Go语言轻量级线程的实现,它们比传统的线程更...

Global site tag (gtag.js) - Google Analytics