并发

有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行。

goroutine

goroutine是Go并行设计的核心。goroutine说到底其实就是线程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。

goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过go关键字实现了,其实就是一个普通的函数。

go hello(a, b, c)

通过关键字go就启动了一个goroutine。我们来看一个例子

package main

import (

"fmt"

"runtime"

)

func say(s string) {

for i := 0; i < 5; i++ {

runtime.Gosched()

fmt.Println(s)

}

}

func main() {

go say("world") //开一个新的Goroutines执行

say("hello") //当前Goroutines执行

}

// 以上程序执行后将输出:

// hello

// world

// hello

// world

// hello

// world

// hello

// world

// hello

我们可以看到go关键字很方便的就实现了并发编程。 上面的多个goroutine运行在同一个进程里面,共享内存数据,不过设计上我们要遵循:不要通过共享来通信,而要通过通信来共享。

runtime.Gosched()表示让CPU把时间片让给别人,下次某个时候继续恢复执行该goroutine。

默认情况下,调度器仅使用单线程,也就是说只实现了并发。想要发挥多核处理器的并行,需要在我们的程序中显式调用 runtime.GOMAXPROCS(n) 告诉调度器同时使用多个线程。GOMAXPROCS 设置了同时运行逻辑代码的系统线程的最大数量,并返回之前的设置。如果n < 1,不会改变当前设置。以后Go的新版本中调度得到改进后,这将被移除。这里有一篇Rob介绍的关于并发和并行的文章:http://concur.rspace.googlecode.com/hg/talk/concur.html#landing-slide

channels

goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。那么goroutine之间如何进行数据的通信呢,Go提供了一个很好的通信机制channel。channel可以与Unix shell 中的双向管道做类比:可以通过它发送或者接收值。这些值只能是特定的类型:channel类型。定义一个channel时,也需要定义发送到channel的值的类型。注意,必须使用make 创建channel:

ci := make(chan int)

cs := make(chan string)

cf := make(chan interface{})

channel通过操作符

ch

v :=

我们把这些应用到我们的例子中来:

package main

import "fmt"

func sum(a []int, c chan int) {

total := 0

for _, v := range a {

total += v

}

c

}

func main() {

a := []int{7, 2, 8, -9, 4, 0}

c := make(chan int)

go sum(a[:len(a)/2], c)

go sum(a[len(a)/2:], c)

x, y :=

fmt.Println(x, y, x + y)

}

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

Buffered

Channels

上面我们介绍了默认的非缓存类型的channel,不过Go也允许指定channel的缓冲大小,很简单,就是channel可以存储多少元素。ch:= make(chan bool, 4),创建了可以存储4个元素的bool 型channel。在这个channel 中,前4个元素可以无阻塞的写入。当写入第5个元素时,代码将会阻塞,直到其他goroutine从channel 中读取一些元素,腾出空间。

ch := make(chan type, value)

value == 0 ! 无缓冲(阻塞)

value > 0 ! 缓冲(非阻塞,直到value 个元素)

我们看一下下面这个例子,你可以在自己本机测试一下,修改相应的value值

package main

import "fmt"

func main() {

c := make(chan int, 2)//修改2为1就报错,修改2为3可以正常运行

c

c

fmt.Println(

fmt.Println(

}

//修改为1报如下的错误:

//fatal error: all goroutines are asleep - deadlock!

Range和Close

上面这个例子中,我们需要读取两次c,这样不是很方便,Go考虑到了这一点,所以也可以通过range,像操作slice或者map一样操作缓存类型的channel,请看下面的例子

package main

import (

"fmt"

)

func fibonacci(n int, c chan int) {

x, y := 1, 1

for i := 0; i < n; i++ {

c

x, y = y, x + y

}

close(c)

}

func main() {

c := make(chan int, 10)

go fibonacci(cap(c), c)

for i := range c {

fmt.Println(i)

}

}

for i := range c能够不断的读取channel里面的数据,直到该channel被显式的关闭。上面代码我们看到可以显式的关闭channel,生产者通过内置函数close关闭channel。关闭channel之后就无法再发送任何数据了,在消费方可以通过语法v,

ok :=

记住应该在生产者的地方关闭channel,而不是消费的地方去关闭它,这样容易引起panic

另外记住一点的就是channel不像文件之类的,不需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束range循环之类的

Select

我们上面介绍的都是只有一个channel的情况,那么如果存在多个channel的时候,我们该如何操作呢,Go里面提供了一个关键字select,通过select可以监听channel上的数据流动。

select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。

package main

import "fmt"

func fibonacci(c, quit chan int) {

x, y := 1, 1

for {

select {

case c

x, y = y, x + y

case

fmt.Println("quit")

return

}

}

}

func main() {

c := make(chan int)

quit := make(chan int)

go func() {

for i := 0; i < 10; i++ {

fmt.Println(

}

quit

}()

fibonacci(c, quit)

}

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

select {

case i :=

// use i

default:

// 当c阻塞的时候执行这里

}

超时

有时候会出现goroutine阻塞的情况,那么我们如何避免整个程序进入阻塞的情况呢?我们可以利用select来设置超时,通过如下的方式实现:

func main() {

c := make(chan int)

o := make(chan bool)

go func() {

for {

select {

case v :=

println(v)

case

println("timeout")

o

break

}

}

}()

}

runtime

goroutine

runtime包中有几个处理goroutine的函数:

Goexit

退出当前执行的goroutine,但是defer函数还会继续调用

Gosched

让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。

NumCPU

返回 CPU 核数量

NumGoroutine

返回正在执行和排队的任务总数

GOMAXPROCS

用来设置可以并行计算的CPU核数的最大值,并返回之前的值。

有疑问加站长微信联系(非本文作者)

go 语言 php并发,go 语言并发相关推荐

  1. c语言map函数k v都是int,Go语言sync.Map(在并发环境中使用的map)

    Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的. 下面来看下并发情况下读写 map 时会出现的问题,代码如下: // 创建一个int到int的映射 m := make(m ...

  2. 03.Go语言的设计哲学之三: 并发

    本文视频地址 Go 语言原生并发原则 1) Go 语言自身实现层面支持面向多核硬件的并发执行和调度 提到并发执行与调度,我们首先想到的就是操作系统对进程.线程的调度.操作系统调度器会将系统中的多个线程 ...

  3. 第09章 Go语言并发,Golang并发

    并发指在同一时间内可以执行多个任务.并发编程含义比较广泛,包含多线程编程.多进程编程及分布式程序等.本章讲解的并发含义属于多线程编程. Go 语言通过编译器运行时(runtime),从语言上支持了并发 ...

  4. python redis处理高并发-Python高并发解决方案实现过程详解

    一.cdn加速 简单说就是把静态资源放到别人服务器上 全称:Content Delivery Network或Content Ddistribute Network,即内容分发网络 基本思路: 尽可能 ...

  5. java设计模式并发_[高并发Java 七] 并发设计模式

    [高并发Java 七] 并发设计模式 [高并发Java 七] 并发设计模式 为什么80%的码农都做不了架构师?>>> 在软件工程中,设计模式(design pattern)是对软件设 ...

  6. [高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  7. java和c语言的区别_C语言为何不会过时?你需要掌握多少种语言?

    关注.星标公众号,不错过精彩内容 整理/排版:付斌 转自:嵌入式ARM 01 为什么C语言不会过时 评价任何一门编程语言,都是招人骂的.永远是这样.就像是春寒料峭的季节, 街上穿棉袄和穿单衣的擦肩而过 ...

  8. window直接运行不需要环境的软件是什么语言开发的_C语言为何不会过时?你需要掌握多少种语言?_C 语言...

    01为什么C语言不会过时 评价任何一门编程语言,都是招人骂的.永远是这样.就像是春寒料峭的季节, 街上穿棉袄和穿单衣的擦肩而过,双方一定是同时在心里出现了两个字:"s b!"这个在 ...

  9. java高并发编程艺术_[高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  10. go语言视频教程_ go语言入门视频教程_go语言实战视频教程

    许多人可能知道go语言的优点在哪里,但他们不知道go语言适合在哪里使用.通过学习go语言视频教程,可以清楚的知道go语言主要用于服务器端开发,其定位是用来开发"大型软件".学习go ...

最新文章

  1. Error in eval(predvars, data, env) : object ‘**‘ not found
  2. 今天写的一个GetProcAddress
  3. 最小生成树(kruskal+prime)
  4. hdu_5701_中位数计数
  5. 【Android Studio】分类整理res/Layouts中的布局文件(创建子目录)
  6. boa + ajax + cgi ajax请求cgi
  7. PYTHON招聘需求与技能体系
  8. selenium 图片上传
  9. Apollo 对表名区分大小写 如何配置MYSQL不区分大小写呢
  10. 余额宝收益冻结是什么意思?
  11. 代码行数统计工具SourceCounter
  12. echo输出到stderr
  13. 数据库系统工程师输给了计算机等级考试二级
  14. 计算机应用有关的论文,关于计算机应用毕业论文范文精选
  15. 电动葫芦断火限位器安装接线电路图
  16. 华为软开云4--玩转流水线
  17. npm安装出现npm err FetchError Invalid response body while trying to fetch httpsregistry.npmjs.orgvu
  18. Eth-Trunk技术原理与配置
  19. 人脸识别之表情识别(七)--面部表情识别阶段综述
  20. 论企业上云的三大阻力!

热门文章

  1. linux中c语言常用内嵌汇编
  2. LeetCode 题 -7. 整数反转
  3. 解决win2003不支持FLV播放的方法
  4. 将下载都是大写字母的网页里面的html转换为小写的简单方式
  5. jQuery框架学习第五天:事件与事件对象
  6. 知道标签html中的标签,我的取包括标签的标签内的内容使用的正则表达式()
  7. 每天进步一点点《ML - K-means》
  8. python end用法在固定位置换行_在Python中链接方法时,换行的样式正确
  9. ERROR manager.SqlManager: Error reading from database: java.sql.SQLException: Streaming result set
  10. C++/C--浮点型数据的二进制表示及其内存存储形式