官术网_书友最值得收藏!

1.4 了解編程語言的發展趨勢

自從上個世紀中葉計算機出現以來,編程語言走了一條長長的發展之路。

C#之父Anders Hejlsberg在2010年所做的一個名為“C# 4.0 and Beyond演講視頻見:http://channel9.msdn.com/posts/matthijs/C-40-and-beyond-by-Anders-Hejlsberg/.”講演中介紹了他對于編程語言發展趨勢的判斷,指出了現代編程語言應該擁有的三大特性(見圖1-14)。

下面向讀者介紹一下這三大特性都包容了哪些內容。

圖1-14 現代編程語言的三大特性

1.4.1 聲明式編程風格

聲明式(Declarative)編程特性體現為告訴計算機“要干什么(Do what?)”,而非“怎么干(How to do?)”。

LINQ就是聲明式編程的典型實例,如果將它與標準的面向對象編程做個對比,就很清楚這兩者的不同了。

下面舉一個實例(參看示例項目ImperativeVsDeclarative)。

假設現在有一個Student對象集合保存了一批學生的信息:

public class Student
{
    public string Name { get;set;}
    public string City { get;set;}
}

需要按City屬性對其進行分組統計(圖1-15)。

圖1-15 對學生數據進行分組統計

下面先介紹一下經典的面向對象實現方法,再與LINQ做個對比。

先定義一個數據結構用于保存數據分組:

class StudentGroup
{
    public string City;
    public List<Student> Students=new List<Student>();
}

編寫以下方法完成整個數據處理工作:

static void GroupStudentByCity()
{
    var students=GetStudents();//獲取學生對象集合
    var results=new List<StudentGroup>();//用于保存分組結果
    //遍歷學生對象集合
    foreach(Student student in students)
    {
        //是否已有此分組?
        StudentGroup res=results.Find(
                item=> item.City==student.City);
        if(res !=null)//有,則向現有分組追加學生
            res.Students.Add(student);
        else//無,則新建一個分組,并且將當前學生對象加入
        {
            StudentGroup newRes=new StudentGroup()
                { City=student.City };
            newRes.Students.Add(student);//為新分組添加學生對象
            results.Add(newRes);//添加新分組
        }
    }
    PrintResult(results);//輸出結果
}

上述代碼清晰地告訴計算機:第一步做什么,第二步做什么……擁有一個明確的執行流程,并且我們可以從代碼中清楚地看到整個數據處理邏輯。

以下為使用LINQ的版本:

static void GroupStudentByCityUseLINQ()
{
    var results=from student in GetStudents()//指定要處理的數據
            group student by student.City into grp//這些數據需要分組
            select ProcessGroup(grp);//對每個分組進行一些加工
    PrintResult(results);//輸出結果
}

可以看到,使用LINQ編程,只需告訴計算機我們“要什么”,而讓計算機自己去決定具體的步驟。

通常,我們將那種“經典的”、需要規定好計算機具體工作步驟的編程語言稱為是“命令式(Imperative)”的,它與具有“聲明式(Declarative)”特性的編程語言對比如圖1-16所示。

在Anders Hejlsberg看來,具備聲明式編程風格是現代編程語言的一個發展方向。

圖1-16 聲明式編程風格與命令式編程風格的對比

1.4.2 動態性編程特性

所謂“動態性(Dynamic)”,其實就是將一些原本在編譯時完成的工作(比如進行類型識別、生成方法調用指令等)推遲到程序運行時才進行。

比較知名的動態編程語言包括Ruby和Python,Web開發中常用的JavaScript也可以歸入動態編程語言的范疇。

使用動態語言編程的好處主要是靈活,開發效率較高。

.NET 4.0以前,CLR是針對靜態編程語言(如C#)而設計的,無法直接運行Ruby和Python等動態語言開發的程序。

.NET 4.0引入了一個“動態語言運行時(Dynamic Language Runtime,DLR)”,在CLR之上提供了一個動態語言的運行環境,從而允許Ruby等動態語言編寫的程序在.NET平臺上運行(見圖1-17)。

圖1-17 .NET 4.0引入的“動態語言運行時(DLR)”

有趣的是,C#和VB.NET等“傳統”語言現在也可以利用DLR的功能,具備部分的動態語言特性,比如C# 4.0就引入了一個新的dynamic關鍵字用于定義“動態類型檢查”的變量,由此可以寫出以下C#代碼:

dynamic d=1;
dynamic result=d.DoSomething();
Console.WriteLine(result);

變量d保存的是一個整數,默認情況下它不可能有一個DoSomething方法除非為其定義一個擴展方法,本書3.6節介紹了擴展方法。,然而,上述代碼卻可以順利地通過編譯,直到運行時才報告引發了一個RuntimeBinderException異常。這說明C#編譯器“看到”dynamic類型的變量時,它不去檢查此變量的真實類型,而將對“d.DoSomething()”這個表達式的類型推斷推遲到程序運行時。

示例項目DynamicExample展示了更多的動態編程技術細節,請讀者自行閱讀。

交叉鏈接

本書第23章《邁進動態編程的世界》對C# 4.0所引入的動態編程特性和DLR的基本原理進行了系統的介紹。

1.4.3 支持并行程序的開發

隨著計算機進入多核時代,編寫支持多核并行的軟件成為潮流。因此,編程語言也要進行相應的變革,以提升并行程序的開發效率。

在.NET 4.0中,引人注目地添加了一個“并行擴展(Parallel Extensions)”,它為所有.NET編程語言提供了一個開發并行程序的平臺。在編程語言層面,主要體現為將“傳統”的LINQ增強為支持并行功能的“并行LINQ(Parallel LINQ,PLINQ)”,由于LINQ本身可與編程語言無縫集成,這實際上相當于“間接地”給.NET編程語言擴充了開發并行程序的能力。

將LINQ轉換為PLINQ非常簡單,很多情況下只需添加一個新的AsParallel子句即可,例如,我們可以很方便地將前一小節中對整數數組進行處理的LINQ查詢轉換為并行查詢:

var results=from student in GetStudents().AsParallel()
    group student by student.City into grp
    select ProcessGroup(grp);

上述代碼在多核CPU上運行時,會自動地劃分為多個子工作任務并行執行。其中關鍵的一點是這些代碼并不假設一定會在多核CPU上運行,也不假定CPU執行核的個數,一切都是“透明”的,用戶將會發現這些代碼在多核CPU上執行會得到更好的性能,但在單核CPU上也能得到正確的結果。

交叉鏈接

本書第19章《并行計算技術基礎》全面介紹了.NET 4.0所引入的并行擴展。.NET并行計算技術是建立于傳統的多線程開發基礎之上的,筆者建議對并行計算感興趣的讀者能通讀本書第4篇《進程、線程與并行計算》的5章(第15~19章),有助于建立起一個比較系統完整的.NET 4.0并行計算知識框架。

1.4.4 .NET編程家族新成員——F#

.NET 4.0除了在基類庫這個層面添加了對并行計算的支持之外,還引入了一種新的可以方便地開發并行程序的.NET編程語言,稱為“F#”。F#本質上是一種函數式編程語言,擁有許多對于面向對象程序員來說非常有趣的特性,比如所有的“變量更確切地說,F#中沒有“變量”的概念,只有“值”的概念。將一個標識符與值關聯的過程稱為“綁定(Bind)”。”都是只讀的,廣泛采用遞歸的方式編程等。

以下F#示例代碼用遞歸的方式定義了一個函數fib,它可以求出Fibonacci數列中指定位置的數值(示例解決方案FibonacciForFS):

let rec fib x=
    match x with
    |0->0
    |1-> 1
    |_-> fib(x-1)+fib(x-2);;

定義好上述遞歸函數之后,“fib 10”就代表第10個Fibonacci數(它等于55)。

使用Visual Studio 2010創建一個F#項目之后,在代碼編輯器中選中要執行的代碼,按Alt+Enter鍵,就會在Visual Studio 2010下部的“F# Interactive(F#交互式)”窗口中看到其執行結果(見圖1-18)。

圖1-18 在Visual Studio 2010中開發F#應用程序

如圖1-18所示,F#的開發方式類似于早期的Basic,即時輸入,即時運行。

擴充閱讀

這種即時輸入、即時運行的開發模式有一個專門的術語,稱為“REPL”,是“Read-Evaluate-Print Loop(讀入→執行→輸出 循環迭代)”的縮寫,許多動態編程語言(比如Python)也擁有這種開發模式。在2010年微軟技術日大會上,C#之父Anders Hejlsberg介紹說他們正在致力于將編譯器的功能開放為編程語言直接可用的API,因此C# 的后繼版本(C# 5.0)將能實現C#代碼的“即時編譯”和“即時運行”,這樣一來,強類型的C#編程語言也可以像動態編程語言一樣,采用REPL的開發模式。

F#其實是一個“混血兒”,它不僅支持函數式編程風格,也能開發傳統的面向對象程序。

F#的獨特特性(比如由于所有“變量”只讀,從而在多線程環境下數據無需加鎖)使得它在并行程序開發、實現一些典型的數學算法、需要對海量數據進行的數據處理等領域大有用武之地。

F#其實是現代編程語言的一個典型范例,C#也將走向類似的道路。

技術春秋

并不新鮮的函數式編程

F#雖然在計算機編程語言歷史上是一種新的編程語言,但它所歸屬的函數式編程語言家族卻有著長達五十多年的悠久歷史。舉個例子,1977年出現的FP就是一種函數式編程語言,它的設計者是John Warner Backus。

這里說說John Warner Backus,他是一名成就卓越的計算機科學家,設計了人類第一個高級程序設計語言Fortran,還發明了著名的“巴克斯范式(Backus Normal Form,BNF)”,它的擴充版本(Extended BNF,EBNF)是當前描述各種程序設計語言語法的常用工具。

所以,許多看上去很“新”的東西其實“很舊”,新路是接在老路后頭的。

主站蜘蛛池模板: 加查县| 建宁县| 耿马| 马边| 浙江省| 色达县| 三都| 南和县| 中牟县| 青川县| 塔城市| 永康市| 孙吴县| 邵武市| 新野县| 聂拉木县| 抚松县| 繁峙县| 富川| 兴安盟| 潮安县| 盈江县| 东源县| 铜山县| 旬邑县| 沙河市| 宜宾市| 铜鼓县| 油尖旺区| 东乌| 通许县| 丘北县| 乌兰浩特市| 特克斯县| 广饶县| 江北区| 嘉义市| 建阳市| 资阳市| 柞水县| 谷城县|