您好,登錄后才能下訂單哦!
這篇文章主要講解了“Python的Generator和Go的Concurrency Pattern有什么聯系嗎”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python的Generator和Go的Concurrency Pattern有什么聯系嗎”吧!
Python 的 generator 和 Go 的 goroutine 都是常用的技法。沒看到有人分析其間關系,所以在此記錄一下。
這兩個概念都是為了 producer-consumer 模式的編程方便發明的。Python 的 generator 和 iterator 以及 iterable objects 一脈相承。Go 出現比 Python 晚,解決同樣的編程便捷性問題,用 channel 和 goroutine 兩個概念。
Go 的做法比較容易理解,因為和教材里的概念一致:producer 和 consumer 各自是一個 goroutine,而一個 goroutine 是一種 green thread —— 自己放棄執行,讓其他 gorotine 有機會占用 CPU,而不依賴一個 preemption 機制(比如 OS kernel)來強制休眠當前 thread 以騰出 CPU 給其他 thread。
producer 把數據寫入一個 channel,consumer 從這個 channel 里讀。一個 channel 就是一個 blocking queue,可以有一個 buffer。讀可以通過 loop 語法。比如
package main func producer(n int) chan int { ch := make(chan int) go func() { // This goroutine is the producer for i := 0; i < n; i++ { ch <- i } close(ch) }() return ch } func main() { // the main goroutine is the consumer for i := range producer(5) { println(i) } }
請注意,上述寫法讓一個 Go 函數創建和返回一個 channel,同時這個 Go 函數啟動一個“發射后不管”的 producer goroutine —— 這是標準 Go 做法,不太符合 C/C++ 的習俗 —— (1)創建 channel(2)啟動 producer 和 consumer threads。這是因為 C/C++ 不支持 high-order functions,或者叫 functionals。具體請參見我的這個回答 什么是函數式編程思維? 這個 Go pattern 和 Python 習俗一致,因為這倆都是 functional programming languages。
上述 Go 的 producer 非常接近 Python 的 generator 的寫法 —— 兩點區別,都是 Python 解釋器代勞的結果:
Python 用戶不需要創建和關閉 channel 了。
ch <- i 這一行可以用 yield i 來代替。
對應的 Python generator 如下
from typing import Iterator def producer(n: int) -> Iterator[int]: for i in range(n): yield i for i in producer(5): print(i)
Python 的 producer 不是一個函數,因為里面沒有 return,而是一個 generator,因為里面有 yield。一個函數返回一個值。而一個 generator 返回一個 iterator。
Go 的 producer 是一個函數,返回一個 channel。Go 里沒有 generator 這樣的“新概念”。
上面 Python generator 里的代碼和 Go producer 里啟動的 goroutine 的代碼幾乎完全一樣,只是把 ch <- i 換成了 yield i。
那么 Python generator 返回的 iterator 到底是個啥呢?其實就是那個 Go channel,或者叫 blocking queue 的。從這個角度看,Python generator 又是一個函數了,返回一個 blocking queue。
Python 里最常用的 generator 莫過于 range —— 上例中也出現了。所以上例中,其實調用 range 的時候,已經創建了一個 Python thread 往 range 返回的 blocking queue 里寫數字。而 producer 只是從這個 queue 里取出數字,再 yield 到 producer 創建的第二個 queue 里,讓 for i in producer(5) 這一行(由 main thread 執行)去讀。
這樣一串三個 Python threads,通過兩個 queues 連成一串,就是 Rob Pike 在著名幻燈片 https://talks.golang.org/2012/concurrency.slide#1 里展示 Go concurrency pattern 里的 pipeline:
不過這里有一個區別,goroutines 是可以并行執行的,如果我們電腦里有多個 CPU cores。不過,Python threads 雖然就是 OS thread 卻受制于 Python 的 GIL,所以任何時候只有一個 Python 在執行中,即使我們有很多 CPU cores。請看https://www.zhihu.com/pin/1343421894465474560
我們設計系統的時候經常需要遵循一個哲學原則 Occam's Razor —— 能達到目的的各種手段里我們選擇最簡單的那個。這也是本專欄名字的由來。在漢語里,這個原則(philosophical principle)叫“刪繁就簡三秋樹”。如果做不到,必然積累還不完的技術債,以至于不可能“領異標新二月花”。
對比上面 Go 和 Python 兩個例子,顯然 Python 例子的代碼更簡單。那么是不是就說明 Python 語言的設計比 Go 更加符合 Occam's Razor 的原則了呢?
恐怕并不盡然。雖然 Python 代碼簡短,但是需要用戶理解更多概念(generator,iterator,以及它們和 functions 以及 queues 的潛在關系)—— 這也是一種開銷。
感謝各位的閱讀,以上就是“Python的Generator和Go的Concurrency Pattern有什么聯系嗎”的內容了,經過本文的學習后,相信大家對Python的Generator和Go的Concurrency Pattern有什么聯系嗎這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。