iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0

我們在之前的章節列舉了Pipeline(管道)的各種優點,但有時候,盡管管道沒有準備好,我們的程序依然還是要幹活
的,這種處理方式,被稱為“Queue”(隊列)。
這意味著,一旦管道的某個階段完成了工作,將其存儲在內存中的臨時位置,以便其他階段可以稍後檢索 它,而你無需保持其引用。在“Channels”章節,我們討論了帶緩沖的通道,你可以把它視作隊列的一 種。
雖然在系統中引入隊列功能非常有用,但它通常是優化程序時希望採用的最後一種技術之一。過早地添加
隊列會隱藏同步問題,例如死鎖和活鎖,並且,隨著程序不斷重構,你可能會發現需要更多或更少的隊
列。
那麽使用隊列有什麽好處呢?隊列通常用來嘗試解決性能問題。隊列幾乎不會減少程序的總運行時間,它
只會讓程序的行為有所不同。

讓我們看個簡單的管道例子:

done := make(chan interface{})
  defer close(done)
  zeros := take(done, 3, repeat(done, 0))
  short := sleep(done, 1*time.Second, zeros)
  long := sleep(done, 4*time.Second, short)
  pipeline := long

這個管道鏈共有4個階段:

  1. 間隔0s,不間斷生成數據流。
  2. 在接收到3條數據後取消前置操作。
  3. 休眠1秒,短耗時階段。
  4. 休眠3秒,長耗時階段。
    我們假設階段1和階段2是即時的,那麽需要關注的是休眠如何影響管道的運行時間。

https://ithelp.ithome.com.tw/upload/images/20231005/20150497lIItrQuEfv.jpg

你可以看到,這個管道耗時13秒。短耗時階段花費了大約9秒。
如果我們給管道加入緩存會怎麽樣?讓我們試試在長短耗時階段之間添加個緩沖:

done := make(chan interface{})
  defer close(done)
  zeros := take(done, 3, repeat(done, 0))
  short := sleep(done, 1*time.Second, zeros)
  buffer := buffer(done, 2, short)    // Buffers sends from short by 2
  long := sleep(done, 4*time.Second, short)
  pipeline := long

https://ithelp.ithome.com.tw/upload/images/20231005/20150497c09Uxc7Usx.png

整個管道依然是13秒,但短耗時階段時長降低到了3秒,看來加入緩存是有效的。
但是如果整個管道仍然需要13秒來執行,這對我們有什麽幫助?
我們來看看下面這個操作:

p := processRequest(done, acceptConnection(done, httpHandler))

這條管道會持續運行直到被取消,並且在取消之前會持續接受連接。
在這期間,你肯定不希望處理連接的 processRequest因acceptConnection接受連接而阻塞,你會希望processRequest是持續可用的,否則程序的用戶可能會發現連接請求被拒絕。

因此,隊列的價值並不是減少了某個階段的運行時間,而是減少了它處於阻塞狀態的時間。 這可以讓程序繼續工作。 在這個例子中,用戶可能會在他們的請求中感受到延遲,但不會被拒絕服務。
通過這種方式,隊列的真正用途是將操作流程分離,以便一個階段的運行時間不會影響另一個階段的運行
時間。
以這種方式解耦來改變整個系統的運行行為,這取決於你的程序,產生的結果可能是好的也可能
是不好的。


上一篇
20.The bridge-channel
下一篇
22.Context
系列文
Concurrency in go 讀書心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言