1、描述javascript
go語言是直接將源碼編譯成二進制機器碼的語言;它支持面向對象、也支持函數式編程;go是強類型語言;Go 編程語言原生支持併發。Go 使用 Go 協程(Goroutine) 和信道(Channel)來處理併發。java
2、基本語法python
一、切片與數組差異:切片是動態化數組,切片是注意二者初始化和函數的區別git
a.初始化差異golang
數組須要指定大小,不指定也會根據初始化的自動推算出大小,不可改變 編程
a:=[...] int {1,2,3} ; a:=[3] int {1,2,3}數組
切片不須要指定大小瀏覽器
a:=[] int {1,2,3}; a:=make([]int,3); a:=make([] int ,3,5)緩存
b.函數傳遞:併發
數組須要明確指定大小,數組是值傳遞,不一樣的數組老是表明不一樣的存儲。
切片不須要明確指定大小,切片是地址傳遞。多個切片若是表示同一個數組的片斷,它們能夠共享數據;所以一個切片和相關數組的其餘切片是共享存儲的。
func changeArray(a [3]int) {//數組
a[0] = 100
}
func changeSlice(s []int) {//切片
s[0] = 100
}
func main(){
a := [...]int{1, 2, 3}
changeArray(a)
fmt.Println(a[0]) //值傳遞,輸出結果:1
var s []int = []int{1, 2, 3, 4}
fmt.Println(len(s), cap((s)))
s = append(s, 6, 7, 8)
fmt.Println(len(s), cap(s))
changeSlice(s)
fmt.Println(s[0]) //地址傳遞,輸出結果:100
}
c.切片和垃圾回收
切片的底層指向一個數組,該數組的實際容量可能要大於切片所定義的容量。只有在沒有任何切片指向的時候,底層的數組內層纔會被釋放,這種特性有時會致使程序佔用多餘的內存。
示例 函數 FindDigits
將一個文件加載到內存,而後搜索其中全部的數字並返回一個切片。
var digitRegexp = regexp.MustCompile("[0-9]+") func FindDigits(filename string) []byte { b, _ := ioutil.ReadFile(filename) return digitRegexp.Find(b) }
這段代碼能夠順利運行,但返回的 []byte
指向的底層是整個文件的數據。只要該返回的切片不被釋放,垃圾回收器就不能釋放整個文件所佔用的內存。換句話說,一點點有用的數據卻佔用了整個文件的內存。
想要避免這個問題,能夠經過拷貝咱們須要的部分到一個新的切片中:
func FindDigits(filename string) []byte { b, _ := ioutil.ReadFile(filename) b = digitRegexp.Find(b) c := make([]byte, len(b)) copy(c, b) return c }
2.數組和Map,數組的輸出按照數組的放置順序,可是Map是無序輸出的,每次遍歷的順序不同;
var m = map[string]int{ "unix": 0, "python": 1, "go": 2, "javascript": 3, "testing": 4, "philosophy": 5, "startups": 6, "productivity": 7, "hn": 8, "reddit": 9, "C++": 10, } var keys []string for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Println("Key:", k, "Value:", m[k]) }
3.go語言中的指針
指針是一種存儲變量內存地址(Memory Address)的變量。
如上圖所示,變量 b
的值爲 156
,而 b
的內存地址爲 0x1040a124
。變量 a
存儲了 b
的地址。咱們就稱 a
指向了 b
。
指針變量的類型爲 *T
,該指針指向一個 T 類型的變量。
&b 獲取b的內存地址值;*a 則是獲取a值對應物理地址值的b值:156;
向函數傳遞指針參數
func change(val *int) { *val = 55 } func main() { a := 58 fmt.Println("value of a before function call is",a) b := &a change(b) fmt.Println("value of a after function call is", a) }
4.那麼何時使用指針接收器,何時使用值接收器?
/* 使用值接收器的方法。 */ func (e Employee) changeName(newName string) { e.name = newName } /* 使用指針接收器的方法。 */ func (e *Employee) changeAge(newAge int) { e.age = newAge }
通常來講,指針接收器可使用在:對方法內部的接收器所作的改變應該對調用者可見時。
指針接收器也能夠被使用在以下場景:當拷貝一個結構體的代價過於昂貴時。考慮下一個結構體有不少的字段。在方法內使用這個結構體作爲值接收器須要拷貝整個結構體,這是很昂貴的。在這種狀況下使用指針接收器,結構體不會被拷貝,只會傳遞一個指針到方法內部使用。
在其餘的全部狀況,值接收器均可以被使用。
5.在方法中使用值接收器 與 在函數中使用值參數
這個話題不少Go語言新手都弄不明白。我會盡可能講清楚。
當一個函數有一個值參數,它只能接受一個值參數。
當一個方法有一個值接收器,它能夠接受值接收器和指針接收器。
讓咱們經過一個例子來理解這一點。
package main import ( "fmt" ) type rectangle struct { length int width int } func area(r rectangle) { fmt.Printf("Area Function result: %d\n", (r.length * r.width)) } func (r rectangle) area() { fmt.Printf("Area Method result: %d\n", (r.length * r.width)) } func main() { r := rectangle{ length: 10, width: 5, } area(r) r.area() p := &r /* compilation error, cannot use p (type *rectangle) as type rectangle in argument to area */ //area(p) p.area()//經過指針調用值接收器 }
6.在方法中使用指針接收器 與 在函數中使用指針參數
和值參數相相似,函數使用指針參數只接受指針,而使用指針接收器的方法可使用值接收器和指針接收器。
package main import ( "fmt" ) type rectangle struct { length int width int } func perimeter(r *rectangle) { fmt.Println("perimeter function output:", 2*(r.length+r.width)) } func (r *rectangle) perimeter() { fmt.Println("perimeter method output:", 2*(r.length+r.width)) } func main() { r := rectangle{ length: 10, width: 5, } p := &r //pointer to r perimeter(p) p.perimeter() /* cannot use r (type rectangle) as type *rectangle in argument to perimeter */ //perimeter(r) r.perimeter()//使用值來調用指針接收器 }
7.並行和併發
並行不必定會加快運行速度,由於並行運行的組件之間可能須要相互通訊。在咱們瀏覽器的例子裏,當文件下載完成後,應當對用戶進行提醒,好比彈出一個窗口。因而,在負責下載的組件和負責渲染用戶界面的組件之間,就產生了通訊。在併發系統上,這種通訊開銷很小。但在多核的並行系統上,組件間的通訊開銷就很高了。因此,並行不必定會加快運行速度!
8.線程與協程區別
線程切換從系統層面遠不止 保存和恢復 CPU上下文這麼簡單。操做系統爲了程序運行的高效性每一個線程都有本身緩存Cache等等數據,操做系統還會幫你作這些數據的恢復操做。因此線程的切換很是耗性能。可是協程的切換隻是單純的操做CPU的上下文,因此一秒鐘切換個上百萬次系統都抗的住。可是協程有一個問題,就是系統並不感知,因此操做系統不會幫你作切換。目前的協程框架通常都是設計成 1:N 模式。所謂 1:N 就是一個線程做爲一個容器裏面放置多個協程。那麼誰來適時的切換這些協程?答案是有協程本身主動讓出CPU,也就是每一個協程池裏面有一個調度器,這個調度器是被動調度的。意思就是他不會主動調度。協程的切換很輕。
9.緩衝信道和非緩衝信道
緩衝的channel:保證往緩衝中存數據先於對應的取數據,簡單說就是在取的時候裏面確定有數據,不然就因取不到而阻塞。
非緩衝的channel:保證取數據先於存數據,就是保證存的時候確定有其餘的goroutine在取,不然就因放不進去而阻塞
3、疑問點
go系列教程:https://studygolang.com/subject/2
信道接入技術及協議:https://blog.csdn.net/fivedoumi/article/details/52776832