<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
下面讓我們一起來看看golang當中常見的演演算法面試題
使用兩個goroutine交替列印1-100之間的奇數和偶數, 輸出時按照從小到大輸出.
package main import ( "fmt" "sync" ) // PrintOddAndEven1 /* func PrintOddAndEven1() { //方法一,使用無緩衝的channel進行通訊 var wg = new(sync.WaitGroup) //注意這裡需要是指標go語言當中都是值傳遞 wg.Add(2) ch := make(chan struct{}) //無緩衝channel defer close(ch) maxVal := 100 go func() { defer wg.Done() for i := 1; i <= maxVal; i++ { ch <- struct{}{} if i%2 == 1 { //奇數 fmt.Printf("the odd is %dn", i) } } }() go func() { defer wg.Done() for i := 1; i <= maxVal; i++ { <-ch //從管道當中讀取一個資料 if i%2 == 0 { //偶數 fmt.Printf("the even is %dn", i) } } }() wg.Wait() } func main() { PrintOddAndEven1() fmt.Println("over") }
下面博主來解釋一下這個的原理 首先因為變數ch是一個無緩衝的channel, 所以只有讀寫同時就緒時才不會阻塞。所以兩個goroutine會同時進入各自的 if 語句(此時 i 是相同的),但是此時只能有一個 if 是成立的,不管goroutine快,都會由於讀channel或寫channel導致阻塞,因此程式會交替列印1-100且有順序。
func PrintOddAndEven2() { var wg = new(sync.WaitGroup) //注意這裡需要是指標go語言當中都是值傳遞 wg.Add(2) oddChan := make(chan struct{}, 1) eveChan := make(chan struct{}, 1) defer close(oddChan) defer close(eveChan) oddChan <- struct{}{} maxVal := 20 go func() { //奇數協程 defer wg.Done() for i := 1; i <= maxVal; i += 2 { <-oddChan fmt.Printf("the odd print %dn", i) eveChan <- struct{}{} //通知偶數協程 } }() go func() { //偶數協程 defer wg.Done() for i := 2; i <= maxVal; i += 2 { <-eveChan fmt.Printf("the even print %dn", i) oddChan <- struct{}{} //通知奇數協程可以列印了 } }() wg.Wait() } func main() { PrintOddAndEven2() fmt.Println("over") }
第二個方法使用這個有緩衝的channel。有緩衝的channel當容量沒有達到上限時寫入不會阻塞在這裡奇數協程的channel容量為1我們提前給他寫入了一個資料因此當偶數和奇數協程都開始讀取資料時,首先讀取到資料的是奇數協程,奇數協程列印完之後在通知偶數協程列印,偶數協程列印完成之後在通知奇數協程重複下去就實現了交替列印的效果。
題目描述非常的簡單就是N個協程交替列印1到maxVal。比如N=3,maxVal是這個100效果應該是第一個協程列印1,第二個協程列印2,第三個協程列印3,第一個協程列印4這樣的效果。
這道題看起來非常的複雜,博主第一次看到這個題的時候也感覺很複雜但是仔細想一下其實並沒有那麼複雜和上面兩題的解題思路是一樣的。下面我們看看這個程式碼如何實現
package main import ( "fmt" "sync" ) func main() { maxVal := 10 res := 0 //用於列印數位 N := 3 //協程的數量 exitChan := make(chan struct{}) //用於退出 chanArr := make([]chan struct{}, N) for i := 0; i < N; i++ { //使用無緩衝的channel chanArr[i] = make(chan struct{}, 1) } num := 0 //記錄輪到那個協程開始列印了 chanArr[0] <- struct{}{} for i := 0; i < N; i++ { go func(i int) { for { <-chanArr[i] if res >= maxVal { exitChan <- struct{}{} break } fmt.Printf("第%d個協程列印%dn", i, res) if num == N-1 {//已經迴圈一輪了輪到第0個協程列印資料了 num = 0 } else { num++ } res++ chanArr[num] <- struct{}{} //第num個協程可以列印資料了 } }(i) } <-exitChan for i := 0; i < N; i++ { close(chanArr[i]) //將管道全部關閉否則會有協程洩漏 } }
其實也非常的簡單也是利用channel來進行這個協程之間的通訊,由於是N個協程之間進行通訊所以了我們定義一個channel的切片首先往第一個channel當中寫入一個資料其他管道沒有寫入資料那麼最先列印的一定是這個第一個協程然後我們在利用一個計數器通知其他協程列印。最後需要注意的是主協程退出時需要將管道全部關閉否則其他協程一致阻塞在那裡就會引起協程洩漏,就只能等到gc的時候才能回收。
問題描述: 使用兩個 goroutine 交替列印序列,一個 goroutinue 列印數位, 另外一個goroutine列印字母, 最終效果如下 12AB34CD56EF78GH910IJ 。
如果鐵子們上面兩題會了那麼這道題就是有手就行的那種和第一道題沒有啥區別
func main() { numChan := make(chan struct{}, 1) chChan := make(chan struct{}, 1) defer close(numChan) defer close(chChan) var wg sync.WaitGroup wg.Add(2) numChan <- struct{}{} go func() { defer wg.Done() for num := 1; num <= 26; num++ { <-numChan fmt.Printf("%d", num) chChan <- struct{}{} } }() go func() { defer wg.Done() for ch := 'A'; ch <= 'Z'; ch++ { <-chChan fmt.Printf("%s", string(ch)) numChan <- struct{}{} } }() wg.Wait() }
同樣的也是利用這個channe進行通訊,利用有緩衝的channel進行通訊。當然也能使用這個無緩衝的channel進行通訊
func main() { numChan := make(chan struct{}) defer close(numChan) var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() for num := 1; num <= 26; num++ { numChan <- struct{}{} fmt.Printf("%d", num) } }() go func() { defer wg.Done() for ch := 'A'; ch <= 'Z'; ch++ { <-numChan fmt.Printf("%s", string(ch)) } }() wg.Wait()
題目描述,給定一個字串使用兩個協程交替列印它。
如果老鐵們上面的拿到題都會了這道題不就是和第一道題是這個一模一樣的嗎?廢話不多說直接上程式碼
func main() { chChan := make(chan struct{}) defer close(chChan) var wg = new(sync.WaitGroup) wg.Add(2) str := "hello world" N := len(str) go func() { defer wg.Done() for i := 0; i < N; i++ { chChan <- struct{}{} if i%2 == 0 { fmt.Println(string(str[i])) } } }() go func() { defer wg.Done() for i := 0; i < N; i++ { <-chChan if i%2 == 1 { fmt.Println(string(str[i])) } } }() wg.Wait() }
當然也可以使用有緩衝的channel在這裡鐵子們可以自行編寫上面寫的太多了。
題目描述使用三個協程分別列印A,B,C列印這個100次。
本題的難度和上面那幾個題完全是一個貨色,我們可以使用三個有緩衝的channel就可以達到目的了。具體細節請看程式碼
package main import ( "fmt" "sync" ) func main() { Achan := make(chan struct{}, 1) Bchan := make(chan struct{}, 1) Cchan := make(chan struct{}, 1) defer close(Achan) defer close(Bchan) defer close(Cchan) Achan <- struct{}{} counter := 0 maxVal := 10 exitChan := make(chan struct{}) //用於退出 go func() { for { <-Achan if counter >= maxVal { exitChan <- struct{}{} break } fmt.Printf("%s ", "A") counter++ Bchan <- struct{}{} } }() go func() { for { <-Bchan if counter >= maxVal { exitChan <- struct{}{} break } fmt.Printf("%s ", "B") counter++ Cchan <- struct{}{} } }() go func() { for { <-Cchan if counter >= maxVal { exitChan <- struct{}{} break } fmt.Printf("%s ", "C") counter++ Achan <- struct{}{} } }() <-exitChan }
在這裡需要注意的點是我們需要close掉這個管道當達到臨界值時,主協程退出但是defer方法會執行這個時候管道一關閉所有協程都會收到退出訊號,另外兩個阻塞在那裡的協程就會退出這樣就沒有這個協程洩漏了。
並行將多個檔案合併到一個檔案當中
MergeFile 把多個檔案合成一個檔案,並行實現子協程優雅退出。採用並行的方式
本題的解題思路同樣的也非常的簡單我們可以定義一個管道並行的讀取檔案寫入到管道當中然後再並行的寫入到檔案當中。非常的簡單
package main import ( "bufio" "fmt" "io" "os" "strconv" "sync" ) // MergeFile 把多個檔案合成一個檔案,並行實現子協程優雅退出 var fileChan = make(chan string, 10000) var writeFish = make(chan struct{}) var wg sync.WaitGroup func readFile(fileName string) { fin, err := os.Open(fileName) if err != nil { fmt.Println(err.Error()) return } defer fin.Close() defer wg.Done() reader := bufio.NewReader(fin) for { line, err := reader.ReadString('n') //注意已經包含換行符了 if err != nil { if err == io.EOF { if len(line) > 0 { line += "n" fileChan <- line } break } else { fmt.Println(err) break } } else if line == "rn" { fmt.Println("進來") continue } else { fileChan <- line } } } func writeFile(fileName string) { fout, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { fmt.Println(err) return } defer fout.Close() defer func() { close(writeFish) }() writer := bufio.NewWriter(fout) //LOOP: // for { // select { // case <-readFish: // close(fileChan)//注意需要關閉因為已經沒有人往裡面寫了 // for line:=range fileChan{ // writer.WriteString(line) //讀取時候已經包含換行符了 // } // break LOOP // case line := <-fileChan: // writer.WriteString(line) //讀取時候已經包含換行符了 // } // // } for { if line, ok := <-fileChan; ok { if line != "rn" { writer.WriteString(line) } } else { break } } writer.Flush() //重新整理 } func main() { wg.Add(3) for i := 1; i <= 3; i++ { fileName := "Dir/" + strconv.Itoa(i) go readFile(fileName) } go writeFile("Dir/merge") wg.Wait() close(fileChan) <-writeFish }
啟動一個協程生成100個數傳送到ch1管道當中,再啟動一個協程從ch1當中取值然後計算平方將其放入ch2管道當中主協程列印
package main import ( "fmt" "sync" ) var wg sync.WaitGroup func f1(ch1 chan int) { defer wg.Done() for i := 0; i < 50; i++ { ch1 <- i } close(ch1) } func f2(ch2 chan int, ch1 chan int) { defer wg.Done() defer close(ch2) for x := range ch1 { ch2 <- x * x } } func main() { wg.Add(2) a := make(chan int, 50) b := make(chan int, 50) go f1(a) go f2(b, a) wg.Wait() for x := range b { fmt.Println(x) } }
到此這篇關於Golang協程常見面試題小結的文章就介紹到這了,更多相關Golang協程面試題內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45