Posted on 2010-09-01 22:50
TWaver 閱讀(1984)
評論(1) 編輯 收藏
作為一名TWaver Evangelist,我的工作目的就是通過與客戶的交流、培訓(xùn)甚至現(xiàn)場支持等方式幫助用戶將TWaver更好地應(yīng)用到客戶項目中,TWaver是這么一款橫跨Java、Web、Flex和.NET等多種技術(shù)平臺的GUI圖形組件,因此我的工作內(nèi)容簡單的說就是:幫助客戶正確使用GUI。
提到GUI線程安全,這是我最想談也最不想談的話題,想談因為此問題不說明白,用戶不清楚項目架構(gòu)設(shè)計之初GUI最需要考慮的問題,往往后期集成測試上線時會出現(xiàn)災(zāi)難性的后果;不想談因為這個話題太大了,從UI單線程的基本事件派發(fā)原理,到Swing、SWT、Flex、Silverlight、WPF甚至是Swing in EclipseRCP,Silverlight in windowsFroms,Applet in MFC等這種“雜交”的情況,這個話題一展開沒有幾個小時剎不住車,甚至需要陷入幫Sun、Adobe、MS向客戶解釋為什么Swing和Silverlight不能設(shè)計成線程安全,F(xiàn)lex和JavaScript為什么不提供線程的問題。
anyway,我桌面已擺著一塊大面包,一大杯濃茶(我哥常鄙視我這樣的喝法糟蹋了好茶葉),希望能有精力一口氣把這該死的問題一次性的解釋透徹。
總得來說目前幾乎所有主流的GUI技術(shù)采用的都是Single UI Thread的實現(xiàn)方式,簡單說你操作任何組件都必須在那個唯一的UI Thread里面進行,否則就會出錯,這里指的也不僅僅是UI組件,大部分時候我們所指的是綁定UI組件的Model部分,因為大部分GUI技術(shù)無論是Swing/SWT的MVC,或Flex和TWaver那樣的MVP,或微軟在WPF和Silverlight中采用的MVP的變異MVVM,這些事件機制最終會導(dǎo)致你對Model層的修改實則間接的也是修改了UI組件,因此在非UI Thread的所有任何其他thread地方你絕對不能碰UI組件已經(jīng)其所綁定的Model。
用TWaver的話說:你操作network,tree,table,sheet,list,chart包括已經(jīng)綁定這些view的databox、element、selectionmodel、alarm、alarmmodel等都必須確保代碼運行在UI Thead中。這里有個地方需要注意我指的是已經(jīng)綁定了View的模型,由于TWaver的DataBox是可以用xml的文本和Serializable的二進制兩種方式進行序列化,因此很多用戶會把twaver的databox數(shù)據(jù)構(gòu)建放在后臺進行,包括TWaver Web整個模型是在J2EE后臺容器操作,這種情況下你只要保證單線程操作即可,并不要求這個線程必須是UI Thread,因為你還沒有綁定View因此沒有UI Thread線程安全的限制。
有些人問為什么要有這些限制,為什么TWaver不能設(shè)計成現(xiàn)場安全的,其實我們的回答和Sun(現(xiàn)在的Oracle)的解釋是一致的Why did we implement Swing this way?,同樣你也可以找到Why did we implement SWT,Flex,WindowsForms,Silverlight,WPF….this way的類似解釋的文章,并不是我們逃脫責(zé)任將痛苦留給客戶,而是因為我們認為多線程的GUI框架非常困難,更不利于用戶的開發(fā)調(diào)試,甚至由于需要進行的各種同步保護反而降低了整體GUI交互效果。
簡單說一個存著number元素的list讓你求sum,如果有多線程并發(fā)在你for循環(huán)的時候動態(tài)修改你怎么辦,你會說加上lock鎖定這個list不就得了,如果這個list非常長需要運行很長時間那豈不其他人都被你堵住了,你會想的想java.util.concurrent的實現(xiàn)那樣分成更多的塊來操作,老大你看看ConcurrentHashMap的一千多行代碼才僅僅解決了map問題,你還會說看看微軟C#4的強大的并行處理Parallel.ForEach函數(shù),即使是這個也僅僅解決了無狀態(tài)和沒有太多耦合邏輯的運算分解,對于復(fù)雜的GUI耦合邏輯目前還沒有靈丹妙藥,Parallel.ForEach也是需要讓你修改代碼的,現(xiàn)在的本子動不動就配上4個8個CPU,但跑在上面的GUI程序性能不會比當(dāng)CPU的強,因為需要GUI密集運算工作時依然只有一個CPU在工作。
這些年并行計算呼聲很高,google這樣的巨人已經(jīng)讓我們老百姓感受到了并行計算的優(yōu)勢,但回到GUI我們依然無法輕松、廉價和透明的體驗到并行的好處,也許有那么一天會到來,但目前階段我并不渴望,以目前的語言類庫基礎(chǔ)如果采用并發(fā)的方式只會讓我們的調(diào)試開發(fā)更痛苦,當(dāng)然最重要的是現(xiàn)在的主要瓶頸已經(jīng)不是GUI的組件了,而是數(shù)據(jù)DATA,從海量的數(shù)據(jù)中查詢獲取到你需要的DATA這個過程才是瓶頸,良好的GUI框架設(shè)計不應(yīng)該將數(shù)據(jù)的獲取與界面的呈現(xiàn)耦合得不可分離,就像TWaver可以秒級的加載萬甚至10萬以上的圖元,但最大的瓶頸是用戶如何更短的時間去獲取和傳輸這些數(shù)據(jù)。
再看看現(xiàn)在熱賣得脫銷iphone4(一萬多甚至最高兩萬二的天價讓我想起當(dāng)年的大哥大時代)和IPad,對應(yīng)這樣的硬件配置用于瀏覽網(wǎng)頁,受發(fā)郵件,聽歌看碟,玩玩小游戲已經(jīng)搓搓有余了,大家抱怨的是信號門,抱怨的是不堪重負的AT&T網(wǎng)絡(luò),題外話Cocoa同樣也不是線程安全的哦:
There may be perceived performance advantages that accrue from using multiple threads with Core Data. In particular, if you execute a large or complex fetch that takes some time, you might execute the full fetch on a background thread. It is important to consider, however, that most of the Application Kit is not thread safe and that you need to take considerable care that object graphs do not get into an inconsistent state.For the most part, the Application Kit is not thread safe; in particular, Cocoa bindings and controllers are not thread safe
因此現(xiàn)階段我們唯一能做的就是老老實實遵守Single UI Thread設(shè)計帶來的限制,這個Thread有很多叫法,在Swing里面稱之為EDT(Event Dispatcher Thread),以下的文章中我們都會簡稱之EDT。
