Windows和Linux對決(多進程多線程)

並行程序設計分爲共享內存和消息驅動(其實就是分佈式內存)兩種,

共享內存:所有CPU共內存,所有CPU由一個操作系統控制的,例如WindowsLinux/UNIX,目前流行的多核、多CPU機器都是屬於這種;

消息驅動:其實就是分佈式內存,CPU由不同的操作系統控制,不同的CPU之間通過網絡通信。例如網格Grid是通過因特網通信、集羣Cluster是通過局域網通信、MPP是通過專有的高速網絡通信。

通過上面的對比,聰明的讀者估計很快就想到了這兩種系統並行程序實現方式的差異:

共享內存:通過操作系統的多進程多線程來完成並行任務,通過進程間通信來完成協作;

消息驅動:通過多臺機器來完成並行任務,通過消息來完成協作。(MPP物理上看是一臺機器,邏輯上是多臺機器)

當然,由於消息驅動系統中每個處理單元都是一臺獨立的機器,對這臺獨立的機器本身當然也可以通過共享內存來實現並行處理。

對於多進程和多線程來說,最有代表性且最常見的的莫過於WindowsLinux(作爲UNIX類操作系統的代表,下同)這兩個操作系統了。

真是冤家路窄,WindowsLinux這對冤家在這裏又碰面了!!

當然,我這裏不是要挑起WindowsLinux誰優誰劣的爭論,對於一個真正的技術人來說,WindowsLinux本身並沒有優劣之分,只有在不同的使用場景下用誰會更好的問題。之所以將WindowsLinux拿來對比,是因爲對比更加容易讓人理解,記憶也更加深刻!

下面我們首先從多進程和多線程的實現機制方面來對比WindowsLinux

                                         多進程多線程實現機制

說起進程和線程,估計大家都會立刻想起那句耳熟能詳的解釋“進程是資源分配的最小單位,線程是運行的最小單位”!。

理論上來說這是對的,但實際上來說就不一定了,例如Windows有進程和線程的概念,而傳統UNIX卻只有進程的概念(例如經典的《UNIX環境高級編程》中就沒有多線程的概念,但SolarisAIX等又有另外的實現,此處暫且不表),Linux也有進程和線程的概念,但實現機制和Windows又不一樣,真是林子大了什麼鳥都有:)

有幾個進程、線程相關的概念首先要簡單介紹一下:

1.1   概念介紹

1.1.1  進程

資源分配最小單位,有的操作系統還是運行最小單位;

1.1.2   線程

運行最小單位,也是CPU調度的最小單位;

1.1.3   ULTKLT

用戶態線程和內核態線程;主要的區分就是“誰來管理”線程,用戶態是用戶管理,內核態是內核管理(但肯定要提供一些API,例如創建)。

簡單對比兩者優劣勢:

1)可移植性:因爲ULT完全在用戶態實現線程,因此也就和具體的內核沒有什麼關係,可移植性方面ULT略勝一籌;

2)可擴展性:ULT是由用戶控制的,因此擴展也就容易;相反,KLT擴展就很不容易,基本上只能受制於具體的操作系統內核;

3)性能:由於ULT的線程是在用戶態,對應的內核部分還是一個進程,因此ULT就沒有辦法利用多處理器的優勢,而KLT就可以通過調度將線程分佈在多個處理上運行,這樣KLT的性能高得多;另外,一個ULT的線程阻塞,所有的線程都阻塞,而KLT一個線程阻塞不會影響其它線程。

4)編程複雜度:ULT的所有管理工作都要由用戶來完成,而KLT僅僅需要調用API接口,因此ULT要比KLT複雜的多;

1.1.4   POSIX

爲了解決不同操作系統之間移植時接口不兼容而制定的接口標準,詳見維基百科解釋:http://zh.wikipedia.org/wiki/POSIX

1.1.5  NPTL

爲了解決Linux原有線程實現機制的缺陷而創立的一個開源項目,從2.4開始就有發佈版本採用NPTL來實現多線程支持了。詳見維基百科解釋http://zh.wikipedia.org/wiki/Native_POSIX_Thread_Library

1.1.6   LWP

Lightweight Process,輕量級進程,看名字有點奇怪,爲什麼叫輕量級進程呢?爲什麼又要用輕量級線程呢?

看了前面ULTKLT的比較,估計大家也發現了一個問題:所謂的ULT,因爲不能利用多處理器的優勢和線程互相阻塞,其實完全不能堪重任,但對於傳統UNIXLinux這類操作系統,內核設計和實現的時候就沒有線程這種對象,那怎麼實現多線程呢?

天才們於是想出了LWP這個招數,說白了這就是一個“山寨版的進程”,完全具有了山寨的一切特徵:

文件系統是原來的進程的;

文件描述符是原來的進程的;

信號處理是原來的進程的;

地址空間是原來的進程的;

但就是進程ID不是原來的進程的,你說像不像BlackBerry的山寨版BlockBerry

 

詳情請參考維基百科解釋:http://en.wikipedia.org/wiki/Light-weight_process

1.2  詳細對比

1.2.1  Windows

在此要向Windows致敬:至少相比Linux來說,Windows在線程上的支持是Linux不能比的(不要跟我提DOS哈)!

Windows的實現機制簡單來說就是前面提到的KLT,即Windows在內核級別支持線程。每個Windows進程至少有一個線程,系統調度的時候也是調度線程。

當創建一個進程時,系統會自動創建它的第一個線程,稱爲主線程。然後,該線程可以創建其他的線程,而這些線程又能創建更多的線程。

Windows已經提供了線程編程系列的API,這裏就不詳述了。

1.2.2  Linux

Linux不同的版本有不同的實現,2.0~2.4實現的是俗稱LinuxThreads的多線程方式,到了2.6,基本上都是NPTL的方式了。下面我們分別介紹。

1.2.2.1 LinuxThreads      

注:以下內容主要參考“楊沙洲 (mailto:[email protected]?subject=Linux 線程實現機制分析&[email protected])國防科技大學計算機學院”的“Linux 線程實現機制分析”。

這種實現本質上是一種LWP的實現方式,即通過輕量級進程來模擬線程,內核並不知道有線程這個概念,在內核看來,都是進程。

Linux採用的“一對一”的線程模型,即一個LWP對應一個線程。這個模型最大的好處是線程調度由內核完成了,而其他線程操作(同步、取消)等都是核外的線程庫函數完成的。

LinuxThreads中,專門爲每一個進程構造了一個管理線程,負責處理線程相關的管理工作。當進程第一次調用pthread_create()創建一個線程的時候就會創建並啓動管理線程。然後管理線程再來創建用戶請求的線程。也就是說,用戶在調用pthread_create後,先是創建了管理線程,再由管理線程創建了用戶的線程。

這種通過LWP的方式來模擬線程的實現看起來還是比較巧妙的,但也存在一些比較嚴重的問題:

1)線程ID和進程ID的問題

按照POSIX的定義,同一進程的所有的線程應該共享同一個進程和父進程ID,而Linux的這種LWP方式顯然不能滿足這一點。

2)信號處理問題

異步信號是以進程爲單位分發的,而Linux的線程本質上每個都是一個進程,且沒有進程組的概念,所以某些缺省信號難以做到對所有線程有效,例如SIGSTOPSIGCONT,就無法將整個進程掛起,而只能將某個線程掛起。

3)線程總數問題

LinuxThreads將每個進程的線程最大數目定義爲1024,但實際上這個數值還受到整個系統的總進程數限制,這又是由於線程其實是核心進程。

4)管理線程問題

管理線程容易成爲瓶頸,這是這種結構的通病;同時,管理線程又負責用戶線程的清理工作,因此,儘管管理線程已經屏蔽了大部分的信號,但一旦管理線程死亡,用戶線程就不得不手工清理了,而且用戶線程並不知道管理線程的狀態,之後的線程創建等請求將無人處理。

5)同步問題

LinuxThreads中的線程同步很大程度上是建立在信號基礎上的,這種通過內核複雜的信號處理機制的同步方式,效率一直是個問題。

6)其他POSIX兼容性問題

Linux中很多系統調用,按照語義都是與進程相關的,比如nicesetuidsetrlimit等,在目前的LinuxThreads中,這些調用都僅僅影響調用者線程。

7)實時性問題

線程的引入有一定的實時性考慮,但LinuxThreads暫時不支持,比如調度選項,目前還沒有實現。不僅LinuxThreads如此,標準的Linux在實時性上考慮都很少。

1.2.2.2   NPTL的實現

NPTLNative POSIX Thread Library,天生的POSIX線程庫。從命名上也可以看出所謂的NPTL就是針對原來的LinuxThreads的,不然爲啥叫“Native”呢:)

本質上來說,NPTL還是一個LWP的實現機制,但相對原有LinuxThreads來說,做了很多的改進。下面我們看一下NPTL如何解決原有LinuxThreads實現機制的缺陷。

1)線程ID和進程ID問題

新的exec函數能夠創建和原有進程ID一樣ID的新進程,這樣所有的線程ID都是一樣的;且/Proc目錄下只會顯示進程的初始線程(初始線程就代表整個進程,類似於Windows的進程中第一個線程s),不會再像以前LinuxThreads機制時每個線程在proc目錄下都有記錄。

2)信號處理問題

內核實現了POSIX要求的線程信號處理機制,發送給進程的信號將由內核分發給一個合適的線程處理,對於致命和全局的信號(例如StopContinue Pending,所有的線程都同步處理。

3)線程總數問題

內核經過擴展,能夠處理任意數量的線程。PID空間經過擴展後,在IA-32系統上能夠最大支持20億線程。

4)管理線程問題

去掉管理進程,管理進程的任務由擴展後的clone函數完成;增加了exit_group的系統調用,用於退出整個進程;

5)信號同步問題

實現了一個叫做FutexFase Userspace Mutex,注意不是Mutex)機制用來完成線程間同步,Futex的主要操作是在用戶態完成的,這樣解決了依靠內核信號機制進行同步的效率問題。詳細請參考http://zh.wikipedia.org/wiki/Futex

 

當然,NPTL雖然做了很多改進,但依然不是100% POSIX兼容的,LinuxThreads的第6個和第7個問題在NPTL機制下依然沒有解決,但這並不掩蓋NPTL帶來的巨大改進,下面是性能對比圖:

NPTL官方的文檔:http://people.redhat.com/drepper/nptl-design.pdf

1.3    對決?

看了前面的分析,大家可能納悶了,這哪裏是對決哦?全部是講Linux的實現了。

其實我也鬱悶,本來應該更加詳細的介紹Windows實現機制的,但由於Linux的不爭氣,全部用來變成對它的分析了。

 

             進程間通信

多進程和多線程本質上就是將原來一個進程或者線程處理的任務分給了多個進程或者線程,也可以說是將原來一個CPU處理的任務分給了多個CPU處理,類似於隨着生產力的發展,原來一個人包打天下的個人英雄主義時代被分工合作的團隊取代一樣。

既然是一個團隊,就必然涉及到分工合作問題,並行程序的設計本質上就是解決“分工”和“合作”的問題。其中“分工”主要是後面講到“並行程序設計模式”,而“合作”則是本篇重點要討論的問題。

相信大家做過項目的都知道所謂合作其實就是“通信”和“衝突解決”。常見的“通信”有開會、電話、郵件、甚至QQ等,無非是爲了交換信息,而“衝突解決”其實就是爲了解決資源不足,大家搶着用的問題。

可能許多菜鳥、大俠以及網上的很多博客都和和我開始一樣,將“通信”和“衝突解決”混爲一談了,一說到進程間通信,就會口若懸河的冒出一大堆名詞:管道、信號量、消息隊列、互斥。。。。。這裏面有的是“通信”(管道、消息隊列),有的是“衝突解決”(信號量、互斥),並不是一類東東。

下面我們分別從“通信”和“衝突解決”兩方面來比較WindowsLinux

1.1        Windows進程間通信

標準(例如《Windows系統編程》裏面提到的)的Windows進程間通信有三個:匿名管道、命名管道(又叫FIFO)、郵槽(MailSlot),實際上常用的還有一個:共享內存。之所以說它不是標準的,我猜測可能是共享內存設計本意不是爲了進程間通信用的,而是爲了內存映射用的。

1.1.1   匿名管道

顧名思義:匿名管道就是“匿名”的“管道”。爲什麼這樣拆開呢?正所謂名如其人,通過名字我們就可以瞭解大概這是個什麼東東。

匿名:之所以叫做“匿名”,當然是因爲沒有名字了,但爲什麼會沒有名字呢?沒有名字又有什麼好處呢?其實很簡單了,“匿名”當然是不想讓其它人知道了,說白了這個“匿名管道”就是隻給父子進程用的,別人不需要也不可能知道名字的。

管道:說道管道,你是否想到了“下水管道”、“煤氣管道”等?對了,和這些管道本質上是一樣的,就是可以傳送東西的,所以叫做管道。要注意匿名管道是“單向流通”(也叫半雙工)的。

1.1.2   命名管道

聰明的你看到這個名字肯定就會產生如下兩個想法,我們就一一來解答:

1)和匿名管道看起來很像

是的,命名管道就是相對匿名管道來說的。

2)命名管道和匿名管道有什麼差別?

對比點

匿名管道

命名管道

備註

消息格式

字符

二進制

命名管道可以控制讀消息的長度

工作模式

半雙工

全雙工

NA

訪問模式

只能在一臺機器上

可以跨網絡

NA

通信模式

一對一,父子進程用

一對多,不同的進程都可以用

一個命名管道可以有多個實例

 

1.1.3   郵槽

郵槽和命名管道類似,都是有名字的,也可以跨網絡進行通信,既然是這樣,爲什麼Windows還要設計郵槽呢?其實也沒有什麼玄虛,說簡單點就是管道都是“點對點”的(命名管道雖然是一對多,但具體的通信還是11進行的),而郵槽是爲了提供一種“廣播”通信機制(王婆賣瓜一下:微軟還不如將郵槽叫做“廣播”:-P)。

下面我們看看郵槽和命名管道的對比:

對比點

郵槽

命名管道

備註

消息格式

數據包

二進制

命名管道可以控制讀消息的長度

工作模式

單向

全雙工

廣播當然是單向的了

訪問模式

可以跨網絡

可以跨網絡

NA

 

1.1.4   共享內存

就像前面提到的一樣,共享內存並不是正統的進程間通信的機制,共享內存其實只不過是Windows“內存映射文件”的一個特殊用法而已。

然而實際中共享內存在進程間通信卻比較常見,從使用方便性上來說,共享內存其實沒有前面介紹的方便(必須結合互斥、事件等一起使用),但爲什麼應用比較多呢?關鍵在於共享內存性能很高

共享內存應該是介於匿名管道和命名管道之間的通信方式,爲什麼這麼說呢?主要有如下幾個原因:

1)共享內存和匿名管道相比:共享內存有名稱,可用於多個進程通信,這點像命名管道;

2)共享內存和命名管道相比:共享內存只能在一臺機器上使用,不能跨網絡,這點和匿名管道類似

3)共享內存是雙向的,這點又和命名管道類似。

 

1.2        Linux進程間通信

介紹完了Windows,介紹Linux就相對輕鬆一些了,雖然WindowsLinux形同水火,打的不可開交,但實際上說白了,它們並不是兩個完全不同的東東,在很多的地方都相似,進程間通信也不例外。

Linux的進程間通信主要有管道、命名管道、消息隊列、共享內存、信號量,其中信號量Semaphore其實是爲了同步用的,因此我這裏就放到下一篇關於同步的博文中去分析。另外,很多人將信號signal也作爲進程間通信,但我認爲信號更像是爲了同步而設計的,因此也放到下一篇博文中去分析。

1.2.1   管道

Linux的管道和Windows的管道是一樣的,這裏就不詳細介紹了。

需要注意的是Linux多了一個叫做“流管道”的東東,除了流管道是全雙工(也就是雙向)外,流管道其它都和管道一樣。

1.2.2   命名管道

Linux的命名管道和Windows的命名管道差異就比較大了,主要對比如下:

對比點

Linux

Windows

備註

消息格式

字節流

二進制

Windows更牛

工作模式

半雙工

全雙工

Windows更牛

訪問模式

只能在一臺機器上

可以跨網絡

Windows更牛

 

1.2.3   消息隊列

這個是Linux特有的進程通信方式,我感覺它有點像郵槽,都能夠實現一對多。不過消息隊列和郵槽的方向正好相反:消息隊列是一堆進程向一個進程發,郵槽是一個進程向一堆進程發

消息隊列還有一個牛B的特性就是消息隊列的消息可以分優先級,進程不一定非要取第一個消息,也可以取指定消息優先級的消息。因此這個特性又可用於多對多通信,即:不同的收方指定不同的優先級。當然實際應用中應該沒人會這麼用,直接創建多個消息隊列是最方便、最簡單、效率最高的方法。

1.2.4   共享內存

Linux的共享內存機制和Windows本質上是一樣的,即都是利用了內存映射的功能。不過Linux將“內存映射到內存”包裝成了“共享內存”,而不像Windows,在使用的時候通過指定不同的參數來區分是“內存映射到文件”還是“共享內存”,所以各位大俠可能在網上有時能夠看到有人將“內存映射”和“共享內存”都說是Linux進程間通信的方式,原因就在這裏。

1.3        OS間進程通信

前面分別介紹了WindowsLinux進程間通信,看到這裏,你肯定會有疑問:什麼?還有OS進程間通信?不同OS之間的進程是不可能通信的!

是的,從操作系統層面來說,Windows的進程和Linux的進程當然是不能通信的,但如果從網絡層面來說,兩臺機器總是要通信的吧?不可能Windows只能和Windows通信,Linux只和Linux通信吧?

說到這裏估計你已經恍然大悟了:不就是Socket通信麼?

是的,就是它,雖然它是用於機器間通信的,但大家想想,機器間通信不就是各個應用程序通信麼?各個應用程序不就是對應操作系統中的一個或者多個進程麼?

 

Windows和Linux對決(線程間同步)

1.1        Windows線程同步

1.1.1   關鍵代碼區Critical Section

所謂“關鍵代碼區”,相信大家看名字也能理解個大概了。首先:它很關鍵,第二:它是代碼區。之所以關鍵,當然目的就是每次只能一個線程能夠進入;既然是代碼區,那就是隻能在一組擁有同樣代碼的線程中用。

那什麼情況下會用到關鍵代碼區呢?當然是要保護多個線程都會用到的東西了,說到這裏,想必你已經猜到了:全局變量和靜態變量

1.1.2   互斥Mutex

互斥看起來和關鍵代碼區是一樣的,都是每次都是隻允許一個線程使用。但互斥和關鍵代碼區相比,具有如下特點:

對比點

關鍵代碼區

互斥

備註

名字

無名字

有名字

NA

跨進程

不能跨進程

可以跨進程

因爲有名字,所以可以跨進程

訪問模式

沒有超時

可以超時

NA

死鎖問題

線程掛了其它線程就只能傻等了

線程掛了,操作系統會通知其它線程

NA

運行環境

用戶區

內核區

所以關鍵代碼區性能要高一些。

 

1.1.3   信號量Semaphore

信號量本質上就是一個計數器,當計數器大於0時就意味着被保護的對象可用。每次申請計數器就減1,釋放就加1.

信號量和互斥體相比,一個最明顯的差別就在於互斥體每次只能有一個線程進行訪問,而信號量可以有多個線程進行訪問。

看到這裏,大家可能都像我開始一樣存在這樣的問題:如果將信號量最大值設置爲1,那麼不就是相當於互斥量了嗎

看起來是一樣的,而且在有些系統上也確實是這樣的,據說是互斥體底層就是信號量來實現的,或者乾脆就沒有互斥體(例如傳統UNIX),但在有的系統上還是有差別的,差別在於:申請和釋放是否要同一個線程完成Windows就是這種形式。互斥體要求同一線程來申請和釋放,而信號量就可以由不同的線程申請和釋放(但是我很難想象這樣做有什麼好處,難倒要給一個線程集中獲取信號量,再來通知另外的線程工作?)。

1.1.4   事件Event

事件本質上是一個系統信號,即:發生了某件事情後,發一個信號給其它關心這件事情的線程。

從事件的本質上來看,事件不是爲了資源保護的,而是爲了線程間通知用的。舉個簡單的例子:Socket接收完一個消息後,將其放入隊列,然後需要通知消息處理線程進行處理。

大家想想,如果沒有事件通知會怎麼樣呢?那接收線程只能設一個定時器或者循環,定時甚至循環去查詢隊列中是否有消息,這種定時和循環處理是對系統性能的極大浪費,所以,有了事件後,就不用這麼浪費了。

 

1.2        Linux線程同步

介紹完WindowsLinux介紹就很方便了,就像上一篇博文提到的一樣,WindowsLinux其實很多地方相似,線程同步也不例外。

1.2.1   關鍵代碼區???

不好意思,Linux沒有這個東東

1.2.2   互斥Mutex

LinuxWindows是一樣的,這裏就不詳細介紹了,需要注意的是傳統UNIX並沒有互斥這個東東,傳統UNIX的互斥是通過二元信號量(即最大值爲1)來實現的。

1.2.3   信號量Semaphore

需要注意的是Linux中信號量有兩種:一種是內核POSIX標準的信號量,一種是用戶態的傳統UNIX IPC信號量。兩者的差別如下:

對比點

POSIX Semaphore

IPC Semaphore

備註

控制者

內核

用戶

IPC Semaphore可以通過semctrl函數修改對外表現。

權限控制

不允許修改

用戶可修改

NA

性能

優於IPC

劣於POSIX

NA

範圍

進程級

系統級

如果進程退出時忘記關閉,POSIX會自動釋放。

POSIX信號量和Windows的信號量是一樣的。

1.2.4   條件變量Conditions

看到這個名字有點莫名其妙,條件變量和線程同步有什麼關係呢?

但其實是Linux(或者是POSIX)的名字取得不好才導致我們很難理解,本質上條件變量就是Windows的事件,作用也是一樣的。唉,如果Linux或者POSIX不想和Windows同名,改成叫“通知”也能讓我們這些小蝦多省點腦力啊:)

1.2.5   信號Signal

類似於“共享內存”也是一種進程間通信的方式一樣,我把信號也列進來作爲線程同步的一種,因爲本質上信號不是爲了線程間同步而設計的,但我們可以利用其作爲線程同步來使用。

如何使用信號呢?既然信號本身就是一種通知(還記得上面我建議將“條件變量”建議改名爲什麼嗎?),那我們就按照通知來使用了,例如:A做完了某事,發一個信號給BB收到後開始啓動做另外一件事。

請注意:和“條件變量”不同的是,條件變量支持廣播機制,而信號只能是點對點,因此實際使用中應該還是“條件變量”方便一些。當然如果是傳統UNIX,那就只能利用信號來進行通知了。

===============================================================================

 

 

注:看我的博客的朋友可能會發現一個現象,我幾乎從來不介紹詳細的函數或者API,而基本上都在“歸納、總結、對比”。這是我個人的一個風格或者理解吧,我認爲函數或者API用的時候查一下就可以了,而在分析和設計的時候,關鍵是要知道有哪些東西可以給我們用,而且要知道我們具體究竟應該用哪個,因此在平時就必須多歸納、總結、對比,而不是背住各種函數和API。

 多機協作(又叫分佈式處理)

嗯,費了九牛二虎之力,終於將WindowsLinux對比完了。你是否準備伸個懶腰,喝杯熱咖啡,聽點音樂來放鬆一下呢?

別急,革命尚未成功,同志還需努力,鐵還得趁熱打。還記得第二篇博文裏面總結的兩種並行實現技術沒有?一個是“多進程多線程”,另一個是“多機協作”,到目前爲止我們基本上只把“多進程多線程”分析完畢了,還有另外一個“多機協作”沒有分析,本篇我們就探討一下“多機協作”這種實現機制。

不過事先申明,由於“多機協作”這種實現機制範圍太廣:小到普通的雙機、中到模擬地球運算的大型機或者巨型機、又如Google這樣NB的公司發明的分佈式文件系統、再到現在熱熱鬧鬧的“雲計算”、或者大家最常用的BT、電騾等P2P技術都屬於這一範疇,且實現太過複雜,不同的系統實現機制也相差很大,限於本人能力,只能“蜻蜓點水”了,如有興趣研究,推薦《分佈式系統概念與設計》這本書,我也沒有讀過,不過據說還不錯。

幸運的是“多機協作”實現機制和“多核編程”並沒有什麼關係,因此即使蜻蜓點水對大家的多核設計水平影響不大。

廢話了半天,讓我們轉到正題上。雖然前面提到了“多機協作”範圍很廣,實現機制也各不相同,但既然大家都劃到“多機協作”這一類裏面,自然有一些基因是相同的。那麼就讓我們對“多機協作”進行一次基因圖譜製作,看看究竟有哪些共同基因。

u       只有一種通信方式:消息。

是的,看到這個不要驚訝,雖然實現形式可以多種多樣,但本質上來說,多機協作系統只有一種通信方式:消息。不管是基於TCP/IPSocket消息,還是基於電信網7號信令的MAP消息,還是內部光纖通信的XX消息,本質上這些都是消息通信。和“多進程多線程”多種多樣的方式來比,顯得有點單薄,因此也就增大了設計的難度。

u       沒有多機同步機制

看到這個是不是更加喫驚?但現實就是如此殘酷,多機協作沒有一個現成可用的同步機制來實現諸如互斥、事件、信號量等同步功能。

但實際應用中你的應用又不得不用到這些東東,例如Google的分佈式文件系統,因此你要自己去實現這些東東,這也增大了設計的難度。

u       沒有“老大”

這裏的老大不是指黑社會的老大哈,相反它是一個好公僕,這個“老大”負責全局的事物管理。嗯,你可能會說“多進程多線程”裏面也沒有老大的啊?

多進程多線程之間確實沒有天然的老大,誰當老大完全是由我們設計人員決定的,但還有一個我們無法決定的老大:操作系統!操作系統在“多進程多線程”實現機制裏面完成了衆多我們沒有怎麼關注但卻不得不用到的功能:進程線程創建、調度、隔離、通信、同步等。

在“多機協作”實現機制中,唯一的老大就是我們設計人員!你要決定如何隔離、如何調度、如何通信、如何同步等所有這些事情,因此設計難度又上一層樓!

舉個最簡單的例子:多進程多線程實現機制中,時間或者時鐘都是操作系統來控制和提供;而在多機協作中,光一個時間或者時鐘同步就能讓你累個半死!!

 

看完上面的初步分析,我們可以得出一個這樣的結論:多機協作只有一個消息通信,然後要基於消息通信來實現同步、通信、管理、調度、分佈式處理等所有你所需要的功能!所以“多機協作”要比“多進程多線程”設計複雜得多。

 

看到這裏,你是否泄氣了呢?本着“不拋棄,不放棄”的精神,我們還是要勇敢面對,而且幸好現在也有很多多機協作的解決方案了。流行的有三個:微軟的COM/DCOMORGCORBASUNJava RMI。這些多機協作(或者叫分佈式)方案封裝了很多底層的通信、調用、同步等機制,使得我們能夠簡單的實現多機協作。

詳細的方案請各位參考COMCORBARMI的相關文檔。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章