您的位置:首页 > 编程语言 > Go语言

go中channel简单使用

2016-05-12 13:33 274 查看
channel是go语言在语言级别提供的goroutine间的通信机制。我们可以使用channel在两个或者多个goroutine之间传递信息。channel是进程内的通信。

channel分为带缓冲的以及不带缓冲的。

ch:=make(chan int )创建一个不带缓冲的channel。ch:=make(chan int,2,5)创建一个带缓冲的channel,其中len(ch)是2,cap(ch)是5.

1.不带缓冲的channel使用:

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
ch := make(chan int)
go ff(ch)
fmt.Println("1", time.Now())
ch <- 2
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
<-ch
fmt.Println("ff end")
fmt.Println("4", time.Now())

}

输出:

1 2016-05-12 12:50:02.4098584 +0800 CST
3 2016-05-12 12:50:02.4118585 +0800 CST
ff end
4 2016-05-12 12:50:04.4149731 +0800 CST
2 2016-05-12 12:50:04.4149731 +0800 CST
main end

5 2016-05-12 12:50:04.4149731 +0800 CST

根据时间可以分析一下程序的工作流程。首先main函数运行到ch<-2时候就阻塞了。不带缓冲的channel接收数据后会阻塞,直到从这个channel中读取数据后,阻塞的程序才恢复。等到ff函数运行到<-ch后,main函数才继续运行。这是ff函数也在运行。从打印的时间可以看出两个函数是并发的。

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
ch := make(chan int)
go ff(ch)
fmt.Println("1", time.Now())
<-ch
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
ch <- 2
fmt.Println("ff end")
fmt.Println("4", time.Now())

}

输出: 1 2016-05-12 13:03:00.3583545 +0800 CST
3 2016-05-12 13:03:00.3603546 +0800 CST
ff end
4 2016-05-12 13:03:02.3634692 +0800 CST
2 2016-05-12 13:03:02.3634692 +0800 CST
main end
5 2016-05-12 13:03:02.3634692 +0800 CST

根据打印的时间信息可以分析,main函数在执行到<-ch时,阻塞。不带缓冲的channel从中读取数据时会阻塞,直到向其中写入数据,阻塞的程序才会继续执行。

2.带缓冲的channel使用:

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
ch := make(chan int, 2)
go ff(ch)
fmt.Println("1", time.Now())
ch <- 2
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
<-ch
fmt.Println("ff end")
fmt.Println("4", time.Now())

}

输出:1 2016-05-12 13:07:27.0666093 +0800 CST
2 2016-05-12 13:07:27.0716096 +0800 CST
main end
5 2016-05-12 13:07:27.0716096 +0800 CST

根据打印信息可以分析,main函数在执行到ch<-2的时候,没有阻塞,而是继续执行。那么为什么ff函数没有来得及运行fmt.Println("3", time.Now())这条程序呢?

从上面不带channel的程序可以看出,fmt.Println("3", time.Now())这句话运行的时间比fmt.Println("1", time.Now())这句话运行的时间要晚。晚多少时间和cpu有关。我们可以先不管。可以做出假设,ff函数里面的fmt.Println("3", time.Now())还没来得及执行,main函数就执行完了,程序就退出了。在这个过程中开的goroutine都不会执行,直接取消。

那么,怎么证明上面那段程序ff没有执行是因为main结束了呢?可以在mian函数最后等待一小会。

修改上面的程序如下:

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
ch := make(chan int, 2)
go ff(ch)
fmt.Println("1", time.Now())
ch <- 2
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())
time.Sleep(1 * time.Second)

}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
<-ch
fmt.Println("ff end")
fmt.Println("4", time.Now())

}

程序输出:1 2016-05-12 13:17:44.0658997 +0800 CST
2 2016-05-12 13:17:44.0708999 +0800 CST
main end
5 2016-05-12 13:17:44.0708999 +0800 CST
3 2016-05-12 13:17:44.0678998 +0800 CST

可以看到,main最后等待了一秒时间,然后ff函数来得及执行fmt.Println("3", time.Now())。但是在ff函数执行time.Sleep(2 * time.Second)等待两秒的时候,mian已经结束了。

更改一下channel读取和写入的顺序,如下:

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
ch := make(chan int, 2)
go ff(ch)
fmt.Println("1", time.Now())
<-ch
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
ch <- 2
fmt.Println("ff end")
fmt.Println("4", time.Now())

}

输出:1 2016-05-12 13:20:06.0520208 +0800 CST
3 2016-05-12 13:20:06.055021 +0800 CST
ff end
4 2016-05-12 13:20:08.0571355 +0800 CST
2 2016-05-12 13:20:08.0571355 +0800 CST
main end
5 2016-05-12 13:20:08.0571355 +0800 CST

根据打印信息可以分析,main函数在执行到<-ch这句话是阻塞,带缓冲的channel如果里面没有数据,从中读取的话会阻塞程序的运行。等到ff函数执行到ch <- 2时,main函数才从阻塞中恢复。

channel切片用例:

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
chs := make([]chan int, 2)
chs[0] = make(chan int)
chs[1] = make(chan int)
go ff(chs[0])
go ff(chs[1])
fmt.Println("1", time.Now())
for _, v := range chs {
fmt.Println(v)
}
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("ff end")
ch <- 1

}

输出:ff end
ff end
1 2016-05-12 18:40:47.5375708 +0800 CST
0x1165a1c0
0x1165a2c0
main end
5 2016-05-12 18:40:47.5425711 +0800 CST

使用range对channel操作时要注意。

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
chs := make(chan int)
go ff(chs)
fmt.Println("1", time.Now())
for v := range chs {
fmt.Println(v)
}
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("ff end")
ch <- 1

}

输出: ff end
1 2016-05-12 18:44:27.3991462 +0800 CST
1

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
F:/ccs/test.go:12 +0x169
exit status 2

exit status 1

程序修改一下,对于单个不带缓冲的channel使用range时,channel需要close。

package main

import (
"fmt"
"time"

"runtime"

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())
chs := make(chan int)
go ff(chs)
fmt.Println("1", time.Now())
for v := range chs {
fmt.Println(v)
}
fmt.Println("main end")
fmt.Println("5", time.Now())

}

func ff(ch chan int) {
fmt.Println("ff end")
ch <- 1
close(ch)

}

输出: 1 2016-05-12 18:46:47.4581571 +0800 CST
ff end
1
main end
5 2016-05-12 18:46:47.4641574 +0800 CST
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  go语言 channel 并发