golang 并发 Concurrency

创建goroutine

func gofun() {
    //helo goroutine
}
go gofun() //在普通函数执行前加关键字go

并行库sync

https://golang.org/pkg/sync/

不要复制 sync中类型的值。 Values containing the types defined in this package should not be copied.

type Cond 条件变量,包含一个locker, 方法有:Broadcast, Signal, Wait

type Locker锁

type Map是个并发安全的map[interface{}]interface{},它为下面两种情形做优化:(1)当给定键的项只写一次但读多次时(如在只增长的缓存中),或(2)当多个goroutine读、写和覆盖不相交键集的项时。方法:Delete, Load, LoadOrStore, Range, Store。

type Mutex,互斥锁,方法:Lock, Unlock。

type Once并发中保证只执行一次,方法:Do.

type Pool对象池,方法:Get, Put。

type RWMutex,读写互斥锁, 方法:Lock, RLock, Rlocker,RUnlock, Unlock

type WaitGroup等待goroutine完成次数。

Channels(推荐使用)

channel可以理解为消息管道,通过channe操作符 <- 发送接收数据

创建channel

ch := make(chan int)

channel操作符

ch <- v    // Send v to channel ch.
v := <-ch  // Receive from ch, and
           // assign value to v.

channel的发送接收会阻塞直到另一边是准备好了,goroutines通过channel就可以避免使用 locks or condition。

Buffered Channels

//Sends to a buffered channel block only when the buffer is full. 
//Receives block when the buffer is empty.
ch := make(chan int, 100)

Range and Close

close(chan) 代表没有更多的值要发送了,channel结束。

通过下面的ok检测是否close

v, ok := <-ch

循环 for i := range c for会直到c close才结束。

注意:发送方负责close channel,在channel close后再发数据会引起panic; 

select

select case 可以让goroutine等待多个通信操作。如果多个case处于ready时,它会从中随机一个。

下面是个例子

package main

import "fmt"

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x: // write
			x, y = y, x+y
		case <-quit: // read
			fmt.Println("quit")
			return
		default:
			fmt.Println("do some thing else")
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()
	fibonacci(c, quit)
}

don't (let computations) communicate by sharing memory, (let them) share memory by communicating (through channels).

不要通过共享内存来进行通信,而是通过通信来共享内存。(就是多用channel)

 

channel values比较

所有的channel type都是可以比较的。如果一个channel值赋值给另外一个,这两个值共享相同的底层数据,它们比较是相等的。

All channel types are comparable types. From the article value parts, we know that non-nil channel values are multi-part values. If one channel value is assigned to another, the two channels share the same underlying part(s). In other words, those two channels represent the same internal channel object. The result of comparing them is true.

 

channel的操作与行为

OperationA Nil ChannelA Closed ChannelA Not-Closed Non-Nil Channel
Closepanicpanicsucceed to close (C)
Send Value Toblock for everpanicblock or succeed to send (B)
Receive Value Fromblock for evernever block (D)block or succeed to receive (A)

 

channel的底层实现:包含3个队列

1、the receiving goroutine queue. 接收值的goroutine队列

2、the sending goroutine queue.发送值的goroutine队列

3、the value buffer queue.值队列,一个环形队列

 

channel作为simple statements在for控制块里使用

package main

import (
	"fmt"
	"time"
)

func main() {
	fibonacci := func() chan uint64 {
		c := make(chan uint64)
		go func() {
			var x, y uint64 = 0, 1
			for ; y < (1 << 63); c <- y { // here
				x, y = y, x+y
			}
			close(c)
		}()
		return c
	}
	c := fibonacci()
	for x, ok := <-c; ok; x, ok = <-c { // here 可以用后面的range来简化
		time.Sleep(time.Second)
		fmt.Println(x)
	}
}

channel在 for-range

for v = range aChannel {
	// use v
}

channel的select-case

package main

import "fmt"

func main() {
	var c chan struct{} // nil
	select {
	case <-c:             // blocking operation
	case c <- struct{}{}: // blocking operation
	default:
		fmt.Println("Go here.")
	}
}

使用select-case实现try-send, try-receive的效果 

package main

import "fmt"

func main() {
	c := make(chan string, 2)
	trySend := func(v string) {
		select {
		case c <- v:
		default: // go here if c is full.
		}
	}
	tryReceive := func() string {
		select {
		case v := <-c: return v
		default: return "-" // go here if c is empty
		}
	}
	trySend("Hello!") // succeed to send
	trySend("Hi!")    // succeed to send
	// Fail to send, but will not block.
	trySend("Bye!")
	// The following two lines will
	// both succeed to receive.
	fmt.Println(tryReceive()) // Hello!
	fmt.Println(tryReceive()) // Hi!
	// The following line fails to receive.
	fmt.Println(tryReceive()) // -
}

 

tobecontinue

其它阅读

https://go101.org/article/channel.html

https://go101.org/article/channel-use-cases.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FatherOfCodingMan

如果觉得有用的话,可以赏点饭钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值