LKY 只有原創內容的 Blog

今之能者,謂能轉貼,至於魯蛇,皆能轉貼。不原創,何以別乎?

  1. 1. 本題 LeetCode 連結:
  2. 2. 本題考核點?
  3. 3. 解法與思路:
    1. 3.1. 1. 所用 Channel 型態與定位?
    2. 3.2. 2. 三個(或說四個) goroutine 之間,如何交接棒?
  4. 4. 完整解題程式碼:
  5. 5. 示意圖:

前言:由於 LeetCode Concurrency(併發) 還沒有 Go 語言版本,我先自行用 Go 語言來解題。為了能在 LeetCode 以外的平台獲得討論,所以我打算逐漸把自己的解題思路寫下。這是我試水溫的第二篇。

本題 LeetCode 連結:

https://leetcode.com/problems/print-in-order/

本題考核點?

指定各種不同順序執行 First(), Second(), Third() 三個 goroutine,但三者都必須以不變順序印出字串,印出順序不受順序執行影響。

goroutine 若不刻意控制,將無法保證執行的先後順序,因此本題就是要考核對 goroutine 順序控制的能力。

解法與思路:

1. 所用 Channel 型態與定位?

本題採用三個 unbuffered channel,並且串在一個 slice 裡。

1
2
3
4
5
// make an array of unbuffered
var streamSync [3]chan interface{}
for i := range streamSync {
streamSync[i] = make(chan interface{})
}

分別是:

  • streamSync[0]: First() 交棒給 Second()
  • streamSync[1]: Second() 交棒給 Third()
  • streamSync[2]: Third() 交棒給 PrintInOrder()

2. 三個(或說四個) goroutine 之間,如何交接棒?

一開始由 PrintInOrder() 依照指定順序啟動三個 goroutine。

再看這三個 goroutine,只有 First() 可以不受限執行 Print,其餘都必須等待各自的 streamSync[i] 訊號,因此可以保證 “First” 先被印出。

1
2
3
4
5
func First(streamSync [3]chan interface{}) {
fmt.Print("First")
streamSync[0] <- nil
wg.Done()
}
1
2
3
4
5
6
func Second(streamSync [3]chan interface{}) {
<-streamSync[0]
fmt.Print("Second")
streamSync[1] <- nil
wg.Done()
}
1
2
3
4
5
func Third(streamSync [3]chan interface{}) {
<-streamSync[1]
fmt.Print("Third")
streamSync[2] <- nil
}
  1. 當 “First” 先被印出之後,交棒給 streamSync[0],然後…

    • streamSync[0] 卡住的 Second() 就可以印出 “Second”
    • streamSync[1] 卡住的 Third() 繼續等待訊號
    • streamSync[2] 卡住的 PrintInOrder() 繼續等待訊號
  2. 當 “Second” 繼續被印出之後,交棒給 streamSync[1],然後…

    • streamSync[1] 卡住的 Third() 就可以印出 “Third”
    • streamSync[2] 卡住的 PrintInOrder() 繼續等待訊號
  3. 當 “Third” 最後被印出之後,交棒給 streamSync[2],然後…

    • streamSync[2] 卡住的 PrintInOrder() 就可以往下執行,最後程式順利結束。

完整解題程式碼:

本題解答程式碼已經窮舉這三個 goroutine 所有啟動順序。

https://play.golang.org/p/cklu-vaxF6w

示意圖:

本文最后更新于 天前,文中所描述的信息可能已发生改变