.NET並發編程-函數式編程

本系列學習在.NET中的並發並行編程模式,實戰技巧

函數式編程

和面向過程編程POP(procedure oriented Programming)面向對象編程OOP(object oriented programming)一樣也是一種編程思維。函數式編程FP(functional programming)和面向過程比較類似,但它更加抽象。

舉個栗子
五子棋,用面向過程編程開發流程就是: ①開始遊戲->②黑子先走->③繪製局勢->④判斷輸贏->⑤輪到白子->⑥繪製局勢->⑦判斷輸贏->⑧返回步驟②->⑨輸出結果,每一步驟寫成單獨的函數就是面向過程的編程思維。優點邏輯很清晰,較少的抽象。

面向對象編程可以從另外一個角度來解決這個問題,本質就是按功能角色劃分,將不同的函數封裝到不同的對象中。黑白雙方一個對象,棋盤對象用於繪製棋盤局勢,規則對象用於判斷輸贏是否五子連心。各個對象之間互相通知,互相協調。優點維護修改方便,如果換成圍棋,直接修改規則對象判斷棋子是否還有「氣」,或者通過面向對象特性去擴展一個對象。理解起來可能比較困難,實際代碼執行可能分散到太多分支上。

面向函數編程呢?函數也是一個獨立的存在,它可以像變量一樣在任何地方出現。因為在面向過程中,不需要將函數做當方法來調用,直接在過程中調用,像Lambda表達式,對一個集合進行快速處理,不需要額外增加方法,調用出編寫一個臨時函數即可。

函數

先思考一個問題,函數一定要當做方法放在一個對象中嗎?答案是否定的,函數並不屬於對象,它是獨立的。在函數式編程思維里,函數可以通過變量,參數等方式傳遞到任何地方,可以在任何地方被調用,它和基本數據類型的待遇一樣。函數式語言一直以來都比較低調,直到並發計算編程瓶頸的出現。

實現並發

並發容易造成什麼問題?從單線程到多線程中,共享狀態的變化容易不受控制。傳統的解決方案就是同步對資源的訪問,避免線程之間的爭用。這樣也不是萬全之策,同步訪問互斥鎖容易出現競態和死鎖。根本的解決方案應該是不依賴於這些變量,既然是變量,就不能依賴於它的狀態。

FP在並發編程上的優勢

  • 不可變性。在FP中沒有變量賦值的概念。對象一旦確定值就不可更改,這在線程之間可以安全的傳輸。

  • 純函數。函數不會修改函數體之外的任何類型的輸入或數據,也就是純函數,沒有副作用(副作用就是相同的輸入可能產生不同的輸出)。輸出取決於輸出,相同的參數傳遞給純函數,輸出只會是相同的值,產生一致的預期行為。

  • 延遲計算。在FP中按需檢索函數的結果,或將大數據流的分析推遲到需要時。

  • 可組合性。組合函數創建更高級的抽象,有利用解決複雜問題。

NULL值的錯誤

高級語言一般都有NULL值類型。Tony Hoare在1965年設計ALGOL面向對象語言時引入了null引用。大約44年後,他為發明他道歉,稱它是10億美元的錯誤。

我無法抗拒引入null引用的誘惑,因為它非常容易實現。這導致了無數的錯誤、漏洞和系統崩潰。

 

 

F#是.NET語言的一部分,是一種函數式編程語言。它就強烈反對null值,鼓勵使用不可變的數據結構,天生適用於並發。C#是在.NET3.5之後也引入函數式範式,增加了諸如lambda表達式和LINQ之類的列表解析功能。因為都在.NET平台上,F#和C#可以互操作,互相調用,有些複雜場景用F#可以用更簡易的方式實現。

to be contiued!
下集:並發函數式編程技術

 

 

寫給普通:

人一旦得到一樣東西
就會忘記當初趴在櫥窗看它的感覺