首页 > 其他分享 >Go语言的并发

Go语言的并发

时间:2023-07-18 21:06:24浏览次数:40  
标签:协程 语言 并发 channel go Go com select 通道

使用协程这种并发模式是趋势,协程的基本要求是:并发执行和可大量创建。

一些语言已经支持协程,下面这个图来自:http://qing.weibo.com/tj/88ca09aa33002ele.html

Go语言的并发_Go

这种并发模式的内核只需要协程和通道就够了。其中协程负责执行代码,通道负责在协程之间传递事件。

 

Go语言的并发_数据_02

        协程是轻量级的线程。在过程式编程中,当调用一个过程的时候,需要等待其执行完才返回。而调用一个协程的时候,不需要等待其执行完,会立即返回。协程十分轻量,Go语言可以在一个进程中执行有数以十万计的协程,依旧保持高性能。而对于普通的平台,一个进程有数千个线程,其CPU会忙于上下文切换,性能急剧下降。随意创建线程可不是一个好主意,但是我们可以大量使用的协程。

        通道是协程之间的数据传输通道。通道可以在众多的协程之间传递数据,数据具体可以值也可以是个引用。通道有两种使用方式。

  • 协程可以试图向通道放入数据,如果通道满了,会挂起协程,直到通道可以为他放入数据为止。
  • 协程可以试图向通道索取数据,如果通道没有数据,会挂起协程,直到通道返回数据为止。

        如此,通道就可以在传递数据的同时,控制协程的运行。有点像事件驱动,也有点像阻塞队列。

 

Go语言创建协程很简单,只需要简单的在函数前用关键字 go即可。

https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/02.7.md 

下面的代码例子是通过2分法,开两个协程分别计算和,然后再合并这两个计算和。

注意,这里的 通道 写入和读取都是阻塞的, 这样就可以保证 两个汇总都计算完了,才会执行 fmt.Println(x, y, x+y)

package main
 
import "fmt"
 
func sum(a []int, c chan int) {
:= 0
for _, v := range
+=
    }
    c <- sum // send sum to c
}
 
func
:= []int{7, 2, 8, -9, 4, 0}
 
:= make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
    x, y :=<-c, <-c // receive from c
 
+y)
}

默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使得Goroutines同步变的更加的简单,而不需要显式的lock。

所谓阻塞,也就是如果读取不到 (value := <-ch)它将会被阻塞,直到有数据接收。

另外,如果ch中有数据,任何发送(ch<-5)将会被阻塞,直到数据被读出。无缓冲channel是在多个goroutine之间同步很棒的工具。

 

Buffered Channels

Go也允许指定channel的缓冲大小,很简单,就是channel可以存储多少元素。 

ch := make(chan type, value) 
value == 0 ! 无缓冲(阻塞) 
value > 0 ! 缓冲(非阻塞,直到value个元素满了才会阻塞)

比如下面的代码会报错误: 

package main
 
import "fmt"
 
func
    c :=make(chanint, 1) //1报错,修改2为3可以正常运行
<- 1
<- 2
<-c)
<-c)
}
错误信息:
throw: all goroutines are asleep - deadlock!
  
1 [chan send]:
  main.main()
/Users/cybercare/go/src/test1/main.go:8 +0x70
  
2 [syscall]:
  created by runtime.main
/usr/local/go/src/pkg/runtime/proc.c:221


Range和Close 

Channel 也可以用 Range 进行遍历。

下面的例子是利用协程计算 斐波那契數列,每次计算出来的值都通过通道打印出来。直到调用close关闭通道。

package main
 
import (
    "fmt"
)
 
func fibonacci(n int, c chan int) {
:= 1, 1
for i := 0; i < n; i++
<-
+y
    }
close(c)
}
 
func
:= make(chan int, 10)
go fibonacci(cap(c), c)
for i := range
        fmt.Println(i)
    }
}

这段代码执行的结果如下:除了前2个数,其他数都是前两个数相加之和。

1
1
2
3
5
8
13
21
34
55

生产者通过关键字close函数关闭channel。关闭channel之后就无法再发送任何数据了,在消费方可以通过语法v, ok := <-ch测试channel是否被关闭。如果ok返回false,那么说明channel已经没有任何数据并且已经被关闭。

记住应该在生产者的地方关闭channel,而不是消费的地方去关闭它

Select

上面介绍的都是只有一个channel的情况,那么如果存在多个channel的时候,我们可以通过select可以监听channel上的数据流动。select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。

在select里面还有default语法,select其实就是类似switch的功能,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)。

http://www.sharejs.com/codes/go/4415

下面代码是斐波那契數列的一个调整,执行结果不确定,这是因为select是随机的选择一个执行的。这里有default函数,default函数也会随机被执行到。如果没有default函数,这个执行结果是固定的。

package main
 
import "fmt"
 
func fibonacci(c, quit chan int) {
:= 1, 1
for
select
case c <-
+y
case <-quit:
"quit")
return
default:
"default")
        }
    }
}
 
func
:= make(chan int)
:= make(chan int)
go func() {
for i := 0; i < 10; i++
<-c)
        }
<- 0
    }()
    fibonacci(c, quit)
}

超时

select 语句使得一个 goroutine 在多个通讯操作上等待。
select 会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个条件分支。当多个都准备好的时候,会随机选择一个。

对 select 的 case ,它只能是  receive, send , assign recv 三者之一。

http://golang.org/pkg/time/#After

https://code.google.com/p/go-wiki/wiki/Timeouts

 

package main
 
import (
    "fmt"
    "time"
)
 
func
:= make(chan int)
:= make(chan bool)
go func() {
for
select
case v := <-c:
                fmt.Println(v)
case <-time.After(5 *
"timeout 5s")
<- true
break
            }
        }
    }()
<-o
}

这里信道 o 的目的就是确保 协程 一直被执行。 我们如果从信道 c 中读取数据超时 5秒的话,就会触发 <-time.After(5 * time.Second), 继而给信道 o 中放入一个数据,从而应用关闭。

 

真实的超时代码应该是类似下面方式的伪代码:

import "time"

c := make(chan os.Error,1)
go func(){ c <- client.Call("Service.Method", args,&reply)}()
select{
  case err :=<-c:
    // use err and reply
  case<-time.After(timeoutNanoseconds):
    // call timed out
}

 

参考资料:

Go语言_并发篇

2.7 并发
https://github.com/astaxie/build-web-application-with-golang/blob/master/02.7.md

Go-简洁的并发
http://www.yankay.com/go-clear-concurreny/

Go语言并发之美
http://qing.weibo.com/tj/88ca09aa33002ele.html

Go的并发模式:超时、继续
http://floss.zoomquiet.org/data/20120427161151/index.html

go 语言并发机制 goroutine 初探
http://xiezhenye.com/2011/11/go-%E8%AF%AD%E8%A8%80%E5%B9%B6%E5%8F%91%E6%9C%BA%E5%88%B6-goroutine-%E5%88%9D%E6%8E%A2.html

Go语言并发
http://www.yiibai.com/go/go_Complicating.html

标签:协程,语言,并发,channel,go,Go,com,select,通道
From: https://blog.51cto.com/u_15588078/6768092

相关文章

  • Go语言Revel框架 准备工作
    一、安装Go参考下面几篇文章:http://golang.org/doc/install 二、设置GOPATH参考下面几篇文章: 三、安装git和hggoget克隆依靠 Git和MercurialInstallingGitInstallingMercurial参考: 四、获得Revelframeworkgogetgithub.com/robfig/revel如果没有设置GOPATH,会下载......
  • Go语言Revel框架 网页请求处理流程
    请求处理流程框架图下图是 Play!Framework 的请求处理流程,Revel框架页是一样的。  图片来自: 对这幅图的说明如下:Playframework是一个无状态的面向请求/回应的框架,所有的HTTP请求都遵循下面的处理流程:框架接收到一个HTTPRequestRouter组件试图从conf/文件中找出对应......
  • Go语言Revel框架,创建一个Web App
    首先请确保Revel环境搭配好了,搭配方式参看: 在命令行依次执行下面命令:cd$GOPATHrevelnewmyapprevelrunmyapp执行的结果提示如下:上面有个提示,CodepathshouldbeinGOPATH,butisinGOROOT。这是因为之前我下载revel代码时,还没有设置GOPATH,goget自动就下载GOROOT目......
  • Win7下安装go1.1beta1
    下载安装Go首先确认你操作系统是64还是32位的,这样在https://code.google.com/p/go/downloads/list下载那个包就知道了。这里我们要下载的是:go1.1beta1.windows-amd64.msigo1.1beta1Windows(x8664-bit)MSIinstaller下载完成后,直接安装即可,安装默认安装的C:\Go目录下,同时......
  • Go语言Revel框架 的聊天室示例解读
    安装Revel框架请参看下面这篇文章:《Go语言Revel框架准备工作》 运行聊天室例子运行聊天室例子只需执行下面命令:$revelrungithub.com/robfig/revel/samples/chat$revelrungithub.com/robfig/revel/samples/chat~~revel!http://robfig.github.com/revel~2013/03/2511:54:4......
  • Go语言Revel框架 聊天室三种通讯方式分析
    三种机制的切换首页相关的网页请求路由如下:#LoginGET  /GET  /demo                 Application.EnterDemo首页显示输入昵称和三种聊天技术选择入口,选择后form提交到Application.EnterDemo页面。跳转到三种具体的聊天技术页面是通......
  • Golang的跨平台编译程序
    Golang支持交叉编译,也就是说你在32位平台的机器上开发,可以编译生成64位平台上的可执行程序。交叉编译依赖下面几个环境变量:$GOARCH  目标平台(编译后的目标平台)的处理器架构(386、amd64、arm)$GOOS     目标平台(编译后的目标平台)的操作系统(darwin、freebsd、linux、wind......
  • Go语言用WebSocket的简单例子
    Go语言标准包里面没有提供对WebSocket的支持,但是在由官方维护的go.net子包中有对这个的支持,需要独立下载, Gowebsocketpackage下载地址:http://code.google.com/p/go.net/websocket。Goget命令下载:gogetcode.google.com/p/go.net/websocket Go实现的WebSocket的文档:http://......
  • Golang做的验证码(2)
    前面一篇文章介绍了2个用Golang做的验证码 这里再补充几个:1、在GAE上使用的Google的验证码(ReCAPTCHA)封装https://github.com/ThePiachu/GAE-Go-ReCAPTCHA这个的核心代码只在下面这个文件:https://github.com/ThePiachu/GAE-Go-ReCAPTCHA/blob/master/ReCaptcha/ReCaptcha.go 2、一......
  • Golang连接Oracle数据库
    Golang连接Oracle的库有很多,比较常见的如下:不过,oralce只提供了oci8的接口,必须通过它来调用,所以下面方案都逃不过相关设置。1、go-db-oracle地址:https://code.google.com/p/go-db-oracle/官方介绍:OracleDriverusingcgotocallOCIlibrariesfromOracleInstantClient11.......