自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python 的 Generator 和 Go 的 Concurrency Pattern

開發(fā) 后端
Python 的 generator 和 Go 的 goroutine 都是常用的技法。沒(méi)看到有人分析其間關(guān)系,所以在此記錄一下。這兩個(gè)概念都是為了 producer-consumer 模式的編程方便發(fā)明的。

Python 的 generator 和 Go 的 goroutine 都是常用的技法。沒(méi)看到有人分析其間關(guān)系,所以在此記錄一下。

這兩個(gè)概念都是為了 producer-consumer 模式的編程方便發(fā)明的。Python 的 generator 和 iterator 以及 iterable objects 一脈相承。Go 出現(xiàn)比 Python 晚,解決同樣的編程便捷性問(wèn)題,用 channel 和 goroutine 兩個(gè)概念。

[[399246]]

Go 的做法

Go 的做法比較容易理解,因?yàn)楹徒滩睦锏母拍钜恢拢簆roducer 和 consumer 各自是一個(gè) goroutine,而一個(gè) goroutine 是一種 green thread —— 自己放棄執(zhí)行,讓其他 gorotine 有機(jī)會(huì)占用 CPU,而不依賴一個(gè) preemption 機(jī)制(比如 OS kernel)來(lái)強(qiáng)制休眠當(dāng)前 thread 以騰出 CPU 給其他 thread。

producer 把數(shù)據(jù)寫入一個(gè) channel,consumer 從這個(gè) channel 里讀。一個(gè) channel 就是一個(gè) blocking queue,可以有一個(gè) buffer。讀可以通過(guò) loop 語(yǔ)法。比如

 

  1. package main 
  2.  
  3. func producer(n int) chan int { 
  4.     ch := make(chan int
  5.     go func() { // This goroutine is the producer 
  6.         for i := 0; i < n; i++ { 
  7.             ch <- i 
  8.         } 
  9.         close(ch) 
  10.     }() 
  11.     return ch 
  12.  
  13. func main() { // the main goroutine is the consumer 
  14.     for i := range producer(5) { 
  15.         println(i) 
  16.     } 

請(qǐng)注意,上述寫法讓一個(gè) Go 函數(shù)創(chuàng)建和返回一個(gè) channel,同時(shí)這個(gè) Go 函數(shù)啟動(dòng)一個(gè)“發(fā)射后不管”的 producer goroutine —— 這是標(biāo)準(zhǔn) Go 做法,不太符合 C/C++ 的習(xí)俗 —— (1)創(chuàng)建 channel(2)啟動(dòng) producer 和 consumer threads。這是因?yàn)? C/C++ 不支持 high-order functions,或者叫 functionals。具體請(qǐng)參見(jiàn)我的這個(gè)回答 什么是函數(shù)式編程思維? 這個(gè) Go pattern 和 Python 習(xí)俗一致,因?yàn)檫@倆都是 functional programming languages。

Python 的做法

上述 Go 的 producer 非常接近 Python 的 generator 的寫法 —— 兩點(diǎn)區(qū)別,都是 Python 解釋器代勞的結(jié)果:

  • Python 用戶不需要?jiǎng)?chuàng)建和關(guān)閉 channel 了。
  • ch <- i 這一行可以用 yield i 來(lái)代替。

對(duì)應(yīng)的 Python generator 如下

 

  1. from typing import Iterator 
  2.  
  3. def producer(n: int) -> Iterator[int]: 
  4.   for i in range(n): 
  5.     yield i 
  6.  
  7. for i in producer(5): 
  8.   print(i) 

比較

Python 的 producer 不是一個(gè)函數(shù),因?yàn)槔锩鏇](méi)有 return,而是一個(gè) generator,因?yàn)槔锩嬗? yield。一個(gè)函數(shù)返回一個(gè)值。而一個(gè) generator 返回一個(gè) iterator。

Go 的 producer 是一個(gè)函數(shù),返回一個(gè) channel。Go 里沒(méi)有 generator 這樣的“新概念”。

上面 Python generator 里的代碼和 Go producer 里啟動(dòng)的 goroutine 的代碼幾乎完全一樣,只是把 ch <- i 換成了 yield i。

那么 Python generator 返回的 iterator 到底是個(gè)啥呢?其實(shí)就是那個(gè) Go channel,或者叫 blocking queue 的。從這個(gè)角度看,Python generator 又是一個(gè)函數(shù)了,返回一個(gè) blocking queue。

Python 里最常用的 generator 莫過(guò)于 range —— 上例中也出現(xiàn)了。所以上例中,其實(shí)調(diào)用 range 的時(shí)候,已經(jīng)創(chuàng)建了一個(gè) Python thread 往 range 返回的 blocking queue 里寫數(shù)字。而 producer 只是從這個(gè) queue 里取出數(shù)字,再 yield 到 producer 創(chuàng)建的第二個(gè) queue 里,讓 for i in producer(5) 這一行(由 main thread 執(zhí)行)去讀。

這樣一串三個(gè) Python threads,通過(guò)兩個(gè) queues 連成一串,就是 Rob Pike 在著名幻燈片 https://talks.golang.org/2012/concurrency.slide#1 里展示 Go concurrency pattern 里的 pipeline:

不過(guò)這里有一個(gè)區(qū)別,goroutines 是可以并行執(zhí)行的,如果我們電腦里有多個(gè) CPU cores。不過(guò),Python threads 雖然就是 OS thread 卻受制于 Python 的 GIL,所以任何時(shí)候只有一個(gè) Python 在執(zhí)行中,即使我們有很多 CPU cores。請(qǐng)看https://www.zhihu.com/pin/1343421894465474560

Occam's Razor

我們?cè)O(shè)計(jì)系統(tǒng)的時(shí)候經(jīng)常需要遵循一個(gè)哲學(xué)原則 Occam's Razor —— 能達(dá)到目的的各種手段里我們選擇最簡(jiǎn)單的那個(gè)。這也是本專欄名字的由來(lái)。在漢語(yǔ)里,這個(gè)原則(philosophical principle)叫“刪繁就簡(jiǎn)三秋樹”。如果做不到,必然積累還不完的技術(shù)債,以至于不可能“領(lǐng)異標(biāo)新二月花”。

對(duì)比上面 Go 和 Python 兩個(gè)例子,顯然 Python 例子的代碼更簡(jiǎn)單。那么是不是就說(shuō)明 Python 語(yǔ)言的設(shè)計(jì)比 Go 更加符合 Occam's Razor 的原則了呢?

恐怕并不盡然。雖然 Python 代碼簡(jiǎn)短,但是需要用戶理解更多概念(generator,iterator,以及它們和 functions 以及 queues 的潛在關(guān)系)—— 這也是一種開銷。

這里只是提醒大家關(guān)注保持設(shè)計(jì)的簡(jiǎn)潔。不在于挖坑比較 Python 和 Go 語(yǔ)言。如果回復(fù)有涉及這樣比較的,恕刪。:-)

責(zé)任編輯:未麗燕 來(lái)源: 知乎
相關(guān)推薦

2020-08-12 08:51:19

Go語(yǔ)言Concurrency后臺(tái)

2017-07-28 10:05:58

Pythonyieldgenerator

2021-03-16 16:16:41

GeneratorWebsockets前端

2022-05-31 09:57:36

編程語(yǔ)言Go語(yǔ)言Python

2013-08-20 13:22:35

PythonGo編程語(yǔ)言

2024-12-13 08:02:10

PythonGenerator懶加載

2009-06-29 08:59:05

hbm的generat

2009-06-29 08:58:06

Hibernate的g

2022-02-09 16:02:26

Go 語(yǔ)言ArraySlice

2022-06-02 13:54:04

Go數(shù)組切片

2009-07-02 09:32:47

generator子元Hibernate

2018-07-30 13:29:04

WebAssemblyGo語(yǔ)言

2018-04-19 14:54:12

2023-03-29 08:03:53

2023-06-10 23:01:41

GrpcProtobuf數(shù)據(jù)

2021-10-18 09:08:27

Go分段棧連續(xù)棧

2023-10-23 19:27:21

Go函數(shù)

2012-06-15 09:56:40

2023-11-21 15:46:13

Go內(nèi)存泄漏

2023-12-30 18:35:37

Go識(shí)別應(yīng)用程序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)