字符串
字符串類型屬于預(yù)定義類型延届,所以不能直接修改字符串。字符串類型代表了一個字符串集合,在底層一個字符串值就是一個字節(jié)序列毡熏。字符串的長度就是字節(jié)序列中字節(jié)的個數(shù)(中文三個字節(jié)舍扰,英文一個字節(jié))倦蚪。一個字符串長度在編譯期間就能確定。使用range 就是unicode 輸出(即中文三個字節(jié)边苹,英文一個字節(jié))陵且。
函數(shù)
函數(shù)也是一個變量,比如 將一個匿名函數(shù)賦值給一個變量个束,那么這個變量每次調(diào)用都會更新內(nèi)部的值慕购。
eg
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
func main() {
f := intSeq()
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
f2 := intSeq()
fmt.Println(f2())
}
output:
1
2
3
1
通道
通道用完一定要關(guān)閉。
no-blocking channel
常規(guī)的通過通道接受和發(fā)送數(shù)據(jù)是阻塞的茬底,我們可以使用default來實現(xiàn)非阻塞的發(fā)送和接受數(shù)據(jù)沪悲,當然 使用非緩沖通道個人認為是一個更好的選擇。
func main() {
messages := make(chan string)
signals := make(chan bool)
select {
case msg := <-messages:
fmt.Println("received message", msg)
default:
fmt.Println("no message received")
}
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message send")
}
select {
case msg := <-messages:
fmt.Println("received messafe", msg)
case sig := <-signals:
fmt.Println("received signal", sig)
default:
fmt.Println("no activity")
}
time.Sleep(time.Second)
}
打印結(jié)果是
no message received
no message send
no activity
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message send")
}
操作之所以打印no message send" 是因為沒有其他goroutine接收數(shù)據(jù)阱表,所以無法寫入數(shù)據(jù)殿如,如果沒有select會造成死鎖贡珊,如果進入第一個分支,可以使用緩沖通道或者(開啟一個讀取通道goroutine 而且必須使用runtime.GOsched 讓開啟的協(xié)程有機會運行)涉馁。
eg
go func() {
// <-messages
fmt.Println("Received from other go routine", <-messages)
}()
runtime.Gosched() // 必須存在门岔,讓goroutine有機會運行
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message send")
}
通道關(guān)閉
只有緩沖通道才需要關(guān)閉,關(guān)閉的通道不能再讀取數(shù)據(jù)烤送,這通常用在協(xié)調(diào)接受者.可以關(guān)閉非空的通道
速率限制
對每個請求采用 time.Tick 進行速率限制
使用golang http 協(xié)議直接開啟 協(xié)程處理請求寒随,還怎么在代碼段限制速率?
微服務(wù)設(shè)計:速率限制帮坚,熔斷妻往,降級
同步
通過通信實現(xiàn)共享內(nèi)存,一塊數(shù)據(jù)只能被唯一的一個goroutine所有叶沛。(*查看一下怎么理解通過通信共享內(nèi)存)
eg:并發(fā)的map
go func() {
var state = make(map[int]int)
for {
select {
case read := <-reads:
read.resp <- state[read.key]
case write := <-writes:// 更新map都是在這里進行同步蒲讯,不會造成并發(fā)map不安全問題
state[write.key] = write.val
write.resp <- true
}
}
}()
share memory by communicating,not commnnicating by sharing
通信來共享內(nèi)存:這種情況一般而言是通過channel傳送數(shù)據(jù)指針,并且約定傳送之后不再修改這個數(shù)據(jù)灰署。
共享內(nèi)存通信:類似聲明一個全局變量判帮,在每個協(xié)程訪問的時候加鎖
不過這不是一定的,在合適的地方使用合適的方式.
不同線程不共享內(nèi)存不用鎖溉箕,線程之間通信和同步都是用channel
eg:
type readOp struct {
key int
resp chan int
}
go func() {
var state = make(map[int]int)
for {
select {
case read := <-reads:
read.resp <- state[read.key]
case write := <-writes:
state[write.key] = write.val
write.resp <- true
}
}
}()
for r := 0; r < 100; r++ {
go func() {
for {
read := &readOp{
key: rand.Intn(5),
resp: make(chan int)}
reads <- read
<-read.resp
atomic.AddUint64(&readOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
通過channel 來控制map的訪問而不是通過mutex
通過channel 通信傳輸?shù)氖侵羔樆耷剑孕薷牡臅r候 也是修改的元數(shù)據(jù)。
返回數(shù)據(jù)resp 為什么用chan 類型因為 只有chan 類型才能監(jiān)控到數(shù)據(jù)已經(jīng)返回肴茄,使用其他數(shù)據(jù)類型無法做到數(shù)據(jù)返回監(jiān)控晌畅。
通過信息通信共享內(nèi)存,而不是共享內(nèi)存通信寡痰,如果用共享內(nèi)存抗楔,可以使用map[] mutex.lock
.一定要注意channel 傳遞的是指針。拦坠。