## 一、說說go語言的main函數
(1)、main函數不能帶參數。
(2)、main函數不能定義返回值。
(3)、main函數所在的包必須為main包。
(4)、main函數中可以使用flag包來獲取和解析命令行參數。
## 二、在go語言中,new和make的區別?
#### 相關知識點:
new和make是內建的兩個函數,主要用來創建分配類型內存。
#### 1、new函數是內建函數,函數定義為
```
func new(Type) *Type
```
new 的作用是初始化一個指向類型的指針(*Type ),使用new函數來分配空間。傳遞給new 函數的是一個類型,不是一個值。返回值是 指向這個新分配的零值的指針。
#### 實例
~~~
package main
import (
"fmt"
)
func main() {
a := new([]int)
fmt.Println(a) //輸出&[],a本身是一個地址
}
~~~
運行結果:
&[]
#### 實例2
~~~
package main
import "fmt"
func main() {
var i *int
fmt.Println("沒有new之前I得值為:", i)
i = new(int)
fmt.Println("new之后I得值為:", i)
}
~~~
執行結果:
```
沒有new之前I得值為: <nil>
new之后I得值為: 0xc0000aa058
```
#### 2、make函數是內建函數,函數定義為
#### 定義
`make`也是用于內存分配的,make(T, args)函數的目的與new(T)不同,make只用于`chan`、`map`以及slice(切片)的內存創建,而且它返回的類型就是這三個類型本身,而不是他們的指針類型,因為這三種類型就是引用類型,所以就沒有必要返回他們的指針了。
```
func make(t Type, size ...IntegerType) Type
```
第一個參數是一個類型,第二個參數是長度。
make返回類型是 T(不是T*)的一個初始化的(不是零值)的實例。
make實例:
~~~
var slice1 []type = make([]type, len)
也可以簡寫為
slice1 := make([]type, len)
~~~
實例:
~~~
package main
import (
"fmt"
)
func main() {
b := make([]int, 1)
fmt.Println(b) //輸出[0],b本身是一個slice對象,其內容默認為0
}
~~~
運行結果:
[0]
#### 注意:
a、簡單來說,new只是分配內存,不初始化內存; 而make即分配又初始化內存。所謂的初始化就是給類型賦初值,比如字符為空,整型為0, 邏輯值為false等。
b、當對slice,map以及channel進行初始化時,使用make比new方式要好,而其他形式的則利用new進行初始化
c、new 的作用是初始化一個指向類型的指針(*T),make 的作用是為 slice,map 或 chan 初始化并返回引用(T)。
d、二者都是內存的分配(堆上),但是`make`只用于slice、map以及channel的初始化(非零值);而`new`用于類型的內存分配,并且內存置為零。
e、`make`返回的還是這三個引用類型本身;而`new`返回的是指向類型的指針。
## 三、go語言中指針運算有哪些?
1、可以通過“&”取指針的地址。
2、可以通過“\*”取指針指向的數據。
## 四、說說go語言中的協程?
1、協程和線程都可以實現程序的并發執行;
2、通過channel來進行協程間的通信;
3、只需要在函數調用前添加go關鍵字即可實現go的協程,創建并發任務;
4、關鍵字go并非執行并發任務,而是創建一個并發任務單元;
#### 協程實例
## 五、go語言中的引用類型包含哪些?
數組切片(slice)、字典(map)、通道(channel)、接口(interface)
## 六、說說go語言中的init函數?*
1、一個包中,可以包含多個init函數
2、程序編譯時,先執行導入包的init函數,再執行本包內的init函數
## 七、說說go語言的同步鎖?
1、當一個goroutine獲得了Mutex后,其他goroutine就只能乖乖的等待,除非該goroutine釋放這個Mutex
2、 RWMutex在讀鎖占用的情況下,會阻止寫,但不阻止讀
3、RWMutex在寫鎖占用情況下,會阻止任何其他goroutine(無論讀和寫)進來,整個鎖相當于由該goroutine獨占
## 八、說說go語言的關于go vendor?
1、基本思路是將引用的外部包的源代碼放在當前工程的vendor目錄下面
2、編譯go代碼會優先從vendor目錄先尋找依賴包
3、有了vendor目錄后,打包當前的工程代碼到其他機器的$GOPATH/src下都可以通過編譯
## 九、go之無緩沖channel(通道)和有緩沖channel(通道)
#### 1、channel定義:
* channel中的一個核心類型,可以把它看成管道。并發核心單元通過它就可以發送或者接收數據進行通訊,這在一定程度上又進一步降低了編程的難度。
* channel是一個數據類型,主要用來解決go程的同步問題以及協程之間數據共享(數據傳遞)的問題。
* channel和map類似,channel也一個對應make創建的底層數據結構的引用。
* 和其它的引用類型一樣,channel的零值也是nil。
* 定義一個channel時,也需要定義發送到channel的值的類型。channel可以使用內置的make()函數來創建
#### 2、go之無緩沖channel(通道)
~~~
package main
import (
"fmt"
)
func main() {
ch := make(chan int) //這里就是創建了一個channel,這是無緩沖管道注意
go func() { //創建子go程
for i := 0; i < 6; i++ {
ch <- i //循環寫入管道
fmt.Println("寫入", i)
}
}()
for i := 0; i < 6; i++ { //主go程
num := <-ch //循環讀出管道
fmt.Println("讀出", num)
}
}
~~~
執行結果:
寫入 0
讀出 0
讀出 1
寫入 1
寫入 2
讀出 2
讀出 3
寫入 3
寫入 4
讀出 4
讀出 5
我們在代碼中 先創建了一個匿名函數的子go程,和main的主go程一起爭奪cpu,但是我們在里面創建了一個管道,無緩沖管道有一個規則那就是必須讀寫同時操作才會有效果,如果只進行讀或者只進行寫那么會被阻塞,被暫時停頓等待另外一方的操作,在這里我們定義了一個容量為0的通道,這就是無緩沖通道,如下圖

無緩沖通道的特點:
* 一次只能傳輸一個數據
* 同一時刻,同時有 讀、寫兩端把持 channel。
* 如果只有讀端,沒有寫端,那么 “讀端”阻塞。
* 如果只有寫端,沒有讀端,那么 “寫端”阻塞。
* 讀channel: <- channel
* 寫channel: channel <- 數據
#### 2、go有緩沖channel(通道)
#### 工作原理:

#### 流程:
* 第 1 步,右側的 goroutine 正在從通道接收一個值。
* 第 2 步,右側的這個 goroutine獨立完成了接收值的動作,而左側的 goroutine 正在發送一個新值到通道里。
* 第 3 步,左側的goroutine 還在向通道發送新值,而右側的 goroutine 正在從通道接收另外一個值。這個步驟里的兩個操作既不是同步的,也不會互相阻塞。
* 第 4 步,所有的發送和接收都完成,而通道里還有幾個值,也有一些空間可以存更多的值。
#### 特點:
* 有緩沖通道就是圖中所示,一方可以寫入很多數據,不用等對方的操作,而另外一方也可以直接拿出數據,不需要等對方寫,但是注意一點(如果寫入的一方把channel寫滿了,那么如果要繼續寫就要等對方取數據后才能繼續寫入,這也是一種阻塞,讀出數據也是一樣,如果里面沒有數據則不能取,就要等對方寫入),而有緩沖channel定義也比較簡單
```
ch:=make(chan int,10)//chan int 只能寫入讀入int類型的數據,10代表容量為10.
```
#### 實例
~~~
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 100) //這里就是創建了一個channel,這是有緩沖管道
go func() { //創建子go程
for i := 0; i < 10; i++ {
ch <- i //循環寫入管道
fmt.Println("寫入", i)
}
}()
for { //主go程
num := <-ch //循環讀出管道
fmt.Println("讀出", num)
}
}
~~~
執行結果:
```
寫入 0
寫入 1
寫入 2
寫入 3
寫入 4
寫入 5
寫入 6
寫入 7
寫入 8
寫入 9
讀出 0
讀出 1
讀出 2
讀出 3
讀出 4
讀出 5
讀出 6
讀出 7
讀出 8
讀出 9
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
D:/diu/model03.go:16 +0x88
exit status 2
```
通過實例我們可以看到產生了死鎖
#### 實例2(解決有緩存通道的死鎖)
#### 方式一:
~~~
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 100) //這里就是創建了一個channel,這是有緩沖管道
go func() { //創建子go程
for i := 0; i < 10; i++ {
ch <- i //循環寫入管道
fmt.Println("寫入", i)
}
}()
for i := 0; i < 10; i++ { //主go程
num := <-ch //循環讀出管道
fmt.Println("讀出", num)
}
}
~~~
執行結果:
```
寫入 0
寫入 1
寫入 2
寫入 3
寫入 4
寫入 5
寫入 6
寫入 7
寫入 8
寫入 9
讀出 0
讀出 1
讀出 2
讀出 3
讀出 4
讀出 5
讀出 6
讀出 7
讀出 8
讀出 9
```
#### 方式二:
#### 使用實例說明有緩沖channel和無緩沖channel
* 同步通信: 數據發送端,和數據接收端,必須同時在線。 —— 無緩沖channel
打電話。打電話只有等對方接收才會通,要不然只能阻塞
* 異步通信:數據發送端,發送完數據,立即返回。數據接收端有可能立即讀取,也可能延遲處理。 —— 有緩沖channel 不用等對方接受,只需發送過去就行
發信息。短信。
## 十、說說go語言的channel特性?
1、給一個 nil channel 發送數據,造成永遠阻塞
2、 從一個 nil channel 接收數據,造成永遠阻塞
3 、給一個已經關閉的 channel 發送數據,引起 panic
4、從一個已經關閉的 channel 接收數據,如果緩沖區中為空,則返回一個零值
5、無緩沖的channel是同步的,而有緩沖的channel是非同步的
## 十一、說說go語言的select機制?
1、select機制用來處理異步IO問題
2、select機制最大的一條限制就是每個case語句里必須是一個IO操作
3、golang在語言級別支持select關鍵字
## 十二、協程,線程,進程的區別?
#### 1、進程
進程是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每個進程都有自己的獨立內存空間,不同進程通過進程間通信來通信。由于進程比較重量,占據獨立的內存,所以上下文進程間的切換開銷(棧、寄存器、虛擬內存、文件句柄等)比較大,但相對比較穩定安全。
#### 2、線程
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。線程間通信主要通過共享內存,上下文切換很快,資源開銷較少,但相比進程不夠穩定容易丟失數據。
#### 3、協程
協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。
## 十三、并發編程概念是什么?
并行是指兩個或者多個事件在同一時刻發生;并發是指兩個或多個事件在同一時間間隔發生。
發偏重于多個任務交替執行,而多個任務之間有可能還是串行的。而并行是真正意義上的“同時執行”
并發編程是指在一臺處理器上“同時”處理多個任務。并發是在同一實體上的多個事件。多個事件在同一時間間隔發生。并發編程的目標是充分的利用處理器的每一個核,以達到最高的處理性能。
## 十四、讀寫鎖或者互斥鎖讀的時候能寫嗎?
Go中讀寫鎖包括讀鎖和寫鎖,多個讀線程可以同時訪問共享數據;寫線程必須等待所有讀線程都釋放鎖以后,才能取得鎖;同樣的,讀線程必須等待寫線程釋放鎖后,才能取得鎖,也就是說讀寫鎖要確保的是如下互斥關系,可以同時讀,但是讀-寫,寫-寫都是互斥的。
- 一、經典(一)
- 二、經典(二)
- 三、經典(三)
- 四、經典(四)
- 五、經典(五)
- 六、經典(六)
- 七、經典(七)
- 八、經典(八)
- 九、經典(九)
- 十、經典(十)
- 十一、經典(十一)
- 十二、經典(十二)
- 其他
- 1、知識點一
- 2、面試集
- 3、負載均衡原理
- 4、LVS相關了解
- 5、微服務架構
- 6、分布式鎖實現原理
- 7、Etcd怎么實現分布式鎖
- 8、Redis的數據結構有哪些,以及實現場景
- 9、Mysql高可用方案有哪些
- 10、Go語言的棧空間管理是怎么樣的
- 11、Goroutine和Channel的作用分別是什么
- 12、Go中的鎖有哪些?三種鎖,讀寫鎖,互斥鎖,還有map的安全的鎖?
- 13、怎么限制Goroutine的數量
- 14、Goroutine和線程的區別?
- 15、中間件原理