21、go语言channel用法
go语言的并发基于:Communication Sequential Process(CSP模型)
Don’t communicate by sharing memory; share memory by communicating(不要通过共享内存来通信,通过通信来共享内存)
chanel作为参数
func worker(id int, c chan int){
for {
fmt.Printf("Worker %d received %d\n",id, <- c)
}
}
func chanDemo(){
var c chan int = make(chan int)
//c := make(chan int)
go worker(0, c)
c <- 1
c <- 2
time.Sleep( time.Millisecond)
}
func main(){
chanDemo()
}
chanel作为数组
func worker(i int, c chan int){
for{
fmt.Printf("Worker %d received %c \n",i, <- c)
}
}
func chanDemo(){
var channels [10]chan int
for i := 0; i < 10; i++{
channels[i] = make(chan int)
go worker(i, channels[i])
}
for i := 0; i < 10; i++{
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++{
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
}
func main(){
chanDemo()
}
channel作为返回值
下方使用channel作为一个函数的返回值,并指定返回的channel只能往里写数据chan<- int
func createWorker(id int) chan<- int {
c := make(chan int)
go func(){
for{
fmt.Printf("Worker %d received %c \n", id, <- c)
}
}()
return c
}
func chanDemo(){
var channels [10]chan<- int
for i := 0; i < 10; i++ {
channels[i] = createWorker(i)
}
for i := 0; i < 10; i++ {
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++ {
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
}
func main(){
chanDemo()
}
channel缓冲区
func worker(id int, c chan int){
for {
fmt.Printf("Worker %d received %c \n", id, <- c)
}
}
func bufferChannelDemo(){
//创建chan时,使用缓冲区,不用发送数据给chan后就马上使用
c := make(chan int,3)
go worker(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
c <- 'D'
time.Sleep( time.Millisecond)
}
func main(){
bufferChannelDemo()
}
channel使用close
chan如果要close的话,一定要是发送方(创建方)close,而不是接收方(使用方)close
func worker(id int, c chan int){
/*for n := range c{
fmt.Printf("Worker %d received %d \n", id, n)
}*/
for {
n, ok := <- c
if !ok {
break
}
fmt.Printf("Worker %d received %d \n", id, n)
}
}
func bufferedChannelDemo(){
//创建chan时,使用缓冲区,不用发送数据给chan后就马上使用
c := make(chan int,3)
go worker(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
c <- 'D'
close(c)
time.Sleep( time.Millisecond)
}
func main(){
bufferedChannelDemo()
}
range遍历channel时,不close channel
func worker(id int, c chan int){
//使用range遍历channel时,会一直收数据,因为外部channel没有close
for n := range c {
fmt.Printf("Worker %d received %c\n",
id, n)
}
}
func createWorker(id int)chan<- int {
c := make(chan int)
go worker(id, c)
return c
}
func chanDemo(){
var channels [10]chan<- int
for i:=0; i<10; i++ {
channels[i] = createWorker(i)
}
for i:=0; i<10; i++{
channels[i] <- 'a' + i
}
for i:=0; i<10; i++{
channels[i] <- 'A' + i
}
time.Sleep(time.Second)
}
func main(){
chanDemo()
}
使用channel等待goroutine结束
type worker struct {
in chan int
done chan bool
}
//使用多个chan来并行完成任务
func doWorker(id int, c chan int, done chan bool){
for n := range c{
fmt.Printf("Worker %d received %c \n", id, n)
//通知任务已经完成
go func(){done <- true}()
}
}
func createWorker(id int) worker {
w := worker{
in : make(chan int),
done : make(chan bool),
}
go doWorker(id, w.in, w.done)
return w
}
func chanDemo(){
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker(i)
}
for i, worker := range workers {
worker.in <- 'a' + i
}
for _, worker := range workers {
<- worker.done
}
for i := 0; i < 10; i++ {
workers[i].in <- 'A' + i
}
for _, worker := range workers {
<- worker.done
}
}
func main(){
chanDemo()
}
使用waitGroup等待goroutine结束
type worker struct {
in chan int
wg *sync.WaitGroup
}
//使用多个chan来并行完成任务
func doWorker(id int, c chan int, wg *sync.WaitGroup){
for n := range c{
fmt.Printf("Worker %d received %c \n", id, n)
//通知任务已经完成
wg.Done()
}
}
func createWorker(id int, wg *sync.WaitGroup) worker {
w := worker{
in : make(chan int),
wg : wg,
}
go doWorker(id, w.in, wg)
return w
}
func chanDemo(){
var wg sync.WaitGroup
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker(i, &wg)
}
wg.Add(20)//设置任务总数
for i, worker := range workers {
worker.in <- 'a' + i
}
for i := 0; i < 10; i++ {
workers[i].in <- 'A' + i
}
//wg.Done()//每个任务做完了需调用,在worker中调用,或者说在协程中调用
wg.Wait()//等待任务完成
}
func main(){
chanDemo()
}
函数式编程
type worker struct {
in chan int
done func()
}
//使用多个chan来并行完成任务
func doWorker(id int, w worker){
for n := range w.in{
fmt.Printf("Worker %d received %c \n", id, n)
//通知任务已经完成
w.done()
}
}
func createWorker(id int, wg *sync.WaitGroup) worker {
w := worker{
in : make(chan int),
done : func(){
wg.Done()
},
}
go doWorker(id, w)
return w
}
func chanDemo(){
var wg sync.WaitGroup
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker(i, &wg)
}
wg.Add(20)//设置任务总数
for i, worker := range workers {
worker.in <- 'a' + i
}
for i := 0; i < 10; i++ {
workers[i].in <- 'A' + i
}
//wg.Done()//每个任务做完了需调用,在worker中调用,或者说在协程中调用
wg.Wait()//等待任务完成
}
func main(){
chanDemo()
}
使用select进行调度
知识点:
1、select的使用
2、定时器的使用
3、在select中使用nil channel
chan里面不管是发数据还是收数据都会阻塞住,要是想非阻塞就使用select
examples:
func generator() chan int{
out := make(chan int)
go func(){
i := 0
for{
time.Sleep( time.Duration(rand.Intn(1500)) * time.Millisecond)
out <- i
i++
}
}()
return out
}
func main (){
var c1, c2 = generator(), generator()
for{
select{
case n := <- c1:
fmt.Println("Received c1:", n)
case n := <- c2:
fmt.Println("Received c2:", n)
}
}
}