Mongoose House

          Technical Edition

          統(tǒng)計(jì)

          留言簿(4)

          積分與排名

          閱讀排行榜

          并行程序測(cè)試

          寫一個(gè)正確的并行程序要比寫順序執(zhí)行程序困難。 其原因是并行程序中潛在的風(fēng)險(xiǎn)和錯(cuò)誤的種類更多 —— 首先,在一個(gè)順序執(zhí)行程序中的錯(cuò)誤同樣會(huì)發(fā)生在并行程序中;其次,并行程序比順序執(zhí)行程序需要關(guān)注更多的風(fēng)險(xiǎn),例如狀態(tài)的競(jìng)爭(zhēng)、數(shù)據(jù)的競(jìng)爭(zhēng)、死鎖、失效的信號(hào)以及活鎖(livelock)。

          同樣測(cè)試并行程序要比測(cè)試順序執(zhí)行程序困難。首先,測(cè)試并行程序的程序本身就是并行程序;其次,并行程序的錯(cuò)誤更難預(yù)測(cè)和重現(xiàn)。在順序執(zhí)行程序中的錯(cuò)誤具有確定性。在給定的輸入和初始狀態(tài)下,一個(gè)順序執(zhí)行程序出錯(cuò)了,那么每次它都會(huì)出錯(cuò),在相同條件下。而一個(gè)并行程序出錯(cuò)了,則有可能是一些不確定因素導(dǎo)致的。

          由于這點(diǎn),重現(xiàn)并行程序的錯(cuò)誤變得非常困難。不僅錯(cuò)誤是隨機(jī)的,而且現(xiàn)象可能也不確定,甚至在同樣的環(huán)境下測(cè)試也可能不發(fā)生錯(cuò)誤,也就是說(shuō)在客戶那里每天都發(fā)生的錯(cuò)誤可能在你的測(cè)試實(shí)驗(yàn)室中就不會(huì)發(fā)生。進(jìn)一步說(shuō),試圖調(diào)試和監(jiān)控并行程序會(huì)引入時(shí)間片(timing)和同步的概念,這也有可能阻止錯(cuò)誤的發(fā)生。在海森堡不確定理論(Heisenberg's uncertainty principle)中,觀察一個(gè)系統(tǒng)的狀態(tài)往往會(huì)改變它。

          所以,基于以上這些令人沮喪的消息,我們應(yīng)該如何保證并行程序可以正常工作呢?我們使用和其他工程學(xué)同樣的方法來(lái)管理并行程序測(cè)試的復(fù)雜性 —— 盡量可能地隔離這個(gè)復(fù)雜性。

          構(gòu)造限制并行交互的程序

          我們可以在程序中全部使用公有的和靜態(tài)的變量。提醒你,這不是一個(gè)好主意,但是它確實(shí)可行 —— 只是這樣做更困難并且程序更脆弱。通過(guò)封裝,我們可以不必關(guān)心所有程序代碼就可以分析某部分程序的行為。

          同樣地,通過(guò)把并行交互(concurrent interactions)封裝在幾個(gè)地方,例如,工作流管理器、資源池、工作隊(duì)列、以及其他的并行對(duì)象中。這樣會(huì)使得分析和測(cè)試并行程序變得更簡(jiǎn)單。一旦并行交互被封裝后,你就可以集中精力測(cè)試并行機(jī)制其自身而不被其他錯(cuò)誤所困擾。

          并行機(jī)制,例如共享的工作隊(duì)列,經(jīng)常被作為從一個(gè)線程到另一個(gè)線程的管道。這些機(jī)制中,通常包含了必要的同步機(jī)制來(lái)保證其中數(shù)據(jù)的完整性 —— 但是被傳入和傳出的對(duì)象屬于應(yīng)用程序而非工作隊(duì)列,所以應(yīng)用程序就有責(zé)任負(fù)責(zé)這些對(duì)象的線程安全。你可以使這些對(duì)象成為線程安全的(最簡(jiǎn)單的辦法就是使它們不可變(immutable)同時(shí)這也是最可靠的辦法),但是另一個(gè)說(shuō)法是:使這種不可變性更有效。

          有效的不可變的對(duì)象(effectively immutable object)是說(shuō),這種對(duì)象在設(shè)計(jì)的時(shí)候并非不可變的 —— 它們可以具有可變的狀態(tài) —— 但是當(dāng)其他線程訪問(wèn)這樣的對(duì)象的時(shí)候,程序通常認(rèn)為它們是不可變的。 換句話說(shuō),一旦你把一個(gè)可變的對(duì)象放入一個(gè)共享的數(shù)據(jù)結(jié)構(gòu)中,此時(shí)這個(gè)對(duì)象可以被其他線程所訪問(wèn)時(shí),確保這個(gè)對(duì)象不會(huì)被其他線程重復(fù)修改。通過(guò)限制主要幾個(gè)類的可變性(mutability)可以限制潛在的不正確的并行行為的范圍。

          代碼(1)是如何有效地利用不變性(immutability)來(lái)大大簡(jiǎn)化測(cè)試的例子。 客戶端代碼向工作管理器(work manager)提交一個(gè)求最大公倍數(shù)的請(qǐng)求,計(jì)算程序(calculation)被表示為Callable<BigInteger[]>,執(zhí)行者(Executor)返回一個(gè)Future<BigInteger[]>表示計(jì)算程序。客戶端代碼等待Future計(jì)算結(jié)果。

          FactorTask這個(gè)類是不可變的,因此是線程安全的,無(wú)需額外的并行交互的測(cè)試。但是FactorTask返回一個(gè)數(shù)組,這個(gè)數(shù)組是可變的。線程間共享可變狀態(tài)需要進(jìn)行同步處理,但是由于應(yīng)用程序代碼的結(jié)構(gòu),因此一旦這個(gè)BigInteger的數(shù)組被FactorTask返回,它的內(nèi)容應(yīng)該是總是不變的,由此,客戶端的代碼可以在Executor框架中使用"piggyback"技術(shù)來(lái)隱式地(implicit)進(jìn)行同步,這樣的話,在訪問(wèn)這個(gè)數(shù)組的時(shí)候就無(wú)需額外的同步機(jī)制。

          ExecutorService?exec? = ?
          class ?FactorTask? implements ?Callable < BigInteger[] > ?{
          private ? final ?BigInteger?number;

          public ?FactorTask(BigInteger?number)?{
          ????
          this .number? = ?number;
          }

          public ?BigInteger[]?call()? throws ?Exception?{
          ????
          return ?factorNumber(number);
          }
          }????

          Future
          < BigInteger[] > ?future? = ?exec.submit( new ?FactorTask(number));
          // ?do?some?stuff
          BigInteger[]?factors? = ?future.get();


          這項(xiàng)技術(shù)幾乎可以被整合到所有的并行機(jī)制中,包括Executor, BlockingQueue, 以及ConcurrentMap。 通過(guò)把有效的不可變的對(duì)象(effectively immutable object)傳遞進(jìn)去然后通過(guò)callback得到返回的有效的不可變的對(duì)象(effectively immutable object),利用這種方法你可以避免許多創(chuàng)建和測(cè)試線程安全類的復(fù)雜性。


          測(cè)試并行的“積木”

          一旦你把并行交互隔離到一些組件(component)中,你就可以集中精力測(cè)試這些組件。由于測(cè)試并行代碼非常困難,所以你應(yīng)該花費(fèi)比測(cè)試順序執(zhí)行代碼更多的時(shí)間來(lái)測(cè)試它。

          以下的一些因素是測(cè)試并行類的一些最佳實(shí)踐。

          ※?測(cè)試是不穩(wěn)定的 —— 你應(yīng)該測(cè)試更長(zhǎng)時(shí)間。
          ※?測(cè)試更多種狀態(tài) —— 只是一遍一遍的測(cè)試相同的輸入和初始狀態(tài)是沒有用的,你應(yīng)該測(cè)試不同的輸入數(shù)據(jù)。
          ※?測(cè)試更多的交互 —— 通過(guò)調(diào)整數(shù)據(jù)輸入的時(shí)間使線程之間的交互達(dá)到不同狀態(tài)。
          ※?增加線程數(shù)量 —— 如果線程數(shù)量太少可能測(cè)試結(jié)果也沒有什么意義,更多的線程將會(huì)造成更多的沖突。
          ※?避免引入同步機(jī)制 —— 如果在測(cè)試程序中引入同步機(jī)制,將會(huì)影響到并行程序測(cè)試的結(jié)果。

          所有這些聽起來(lái)就像是一大堆工作要做,而事實(shí)也確實(shí)如此。但是通過(guò)使用一些被廣泛應(yīng)用而且經(jīng)過(guò)充分測(cè)試的組件,我們可以大大減少測(cè)試并行程序的工作量。而且通過(guò)重用已知的組件庫(kù),譬如java.util.concurrent包,你可以進(jìn)一步地減少測(cè)試的負(fù)擔(dān)。

          ---
          原文:
          http://www.theserverside.com/tt/articles/article.tss?l=TestingConcurrent

          posted on 2006-09-28 12:17 Mongoose 閱讀(1332) 評(píng)論(1)  編輯  收藏

          評(píng)論

          # re: 并行程序測(cè)試 2006-09-28 23:11 壞男孩

          測(cè)試是比較有前途的  回復(fù)  更多評(píng)論   


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 塘沽区| 泸定县| 从化市| 安国市| 湛江市| 仪陇县| 同江市| 西藏| 扶余县| 冕宁县| 定远县| 万源市| 拉孜县| 乃东县| 镇安县| 永福县| 南郑县| 绥阳县| 金寨县| 阜南县| 同心县| 水富县| 仙居县| 精河县| 舞钢市| 柳河县| 榆林市| 内黄县| 巴青县| 邵武市| 普兰县| 屏东县| 沂南县| 临夏市| 日照市| 佛冈县| 越西县| 三亚市| 大荔县| 遂宁市| 黔江区|