asgard項(xiàng)目已經(jīng)準(zhǔn)備了一段時(shí)間了,不過有些基本問題還需要考慮,也有一些是新發(fā)現(xiàn)的問題,以及自認(rèn)為比較好的解決辦法。
通過第2、第4條的仔細(xì)研究,已經(jīng)漸漸完善、明確了動(dòng)態(tài)部分和靜態(tài)部分的關(guān)系,使得Method包裝類所完成的功能漸漸接近于一個(gè)函數(shù),而元信息則脫離具體的對(duì)象提升到全局(當(dāng)然還有些小問題沒有解決)。
1、參數(shù)名稱的問題。為了與SOAP等基于XML的協(xié)議兼容,必須開始就把參數(shù)名稱考慮在內(nèi)。
代碼經(jīng)過C++編譯器編譯以后,類型、變量名稱等都不復(fù)存在,唯一留下的是RTTI,顯然不能解決這個(gè)問題。所以只能在定義時(shí)把它加入。
BEGIN_SERVICE(TestService)
METHOD (void(in<int>, inout<string>, out<short>), method1, index, info, result);
END_SERVICE()
如果使用這種方式,index, info, result分別表示變量名字,在宏里面轉(zhuǎn)成字符串,看起來好像不太舒服,而且宏不支持參數(shù)個(gè)數(shù)變化。
BEGIN_SERVICE(TestService)
METHOD (void(in<int>, inout<string>, out<short>), method1, "(index, info, result)");
METHOD (int(in<int>, inout<string>), method2, "result(index, info)");
END_SERVICE()
這種可能稍稍舒服一點(diǎn),在Method構(gòu)造函數(shù)或其它地方解析這個(gè)字符串,賦給各個(gè)參數(shù)。不過它的缺點(diǎn)是把編譯期應(yīng)該檢查出來的錯(cuò)誤,延遲到運(yùn)行期。如果在編譯期來做,又會(huì)使接口描述變得很復(fù)雜。
只是為了得到參數(shù)的名字,就要增加這么些麻煩。
c++0x只是一個(gè)庫的標(biāo)準(zhǔn),估計(jì)XTI也不會(huì)加入這些特性,而且c++0x很遙遠(yuǎn),所以暫時(shí)以這種方式來做。
暫時(shí)的解決辦法:
BEGIN_SERVICE(TestService)
METHOD (void(in<int>, inout<string>, out<short>), method1);
METHOD (int(in<int>, inout<string>), method2);
BEGIN_SERVICE_DEFINE(TestService)
METHOD_DEFINE (method1, "(index, info, result)", test_func);
METHOD_DEFINE (method2, "result(index, info)", &Test::test_method);
END_SERVICE_DEFINE()
END_SERVICE()
缺點(diǎn)是參數(shù)名稱中的錯(cuò)誤,要延遲到運(yùn)行期才能解決掉。
2、服務(wù)對(duì)象的大小。
如果客戶端要調(diào)用其中一個(gè)方法,生成一個(gè)TestService,則構(gòu)造成本太高,特別是一個(gè)服務(wù)中有多個(gè)方法的時(shí)候。一個(gè)服務(wù)容納了多個(gè)方法,而每個(gè)方法包含一個(gè)vector,以及各個(gè)參數(shù),這還沒考慮以后的擴(kuò)展。
所以應(yīng)該修改調(diào)用方式,讓它只只需要生成調(diào)用所需的最小(少)對(duì)象。
這部分考慮還不成熟,暫時(shí)可以不管它,而以方法作為考慮的對(duì)象。
暫時(shí)想到的解決辦法:Method對(duì)象中的parameters容器和各個(gè)參數(shù),只在調(diào)用operator ()或async_call時(shí),才真正生成出來。
這樣的話,Method對(duì)象中僅保存一個(gè)空的vector。
甚至這個(gè)vector也可以只是一個(gè)空指針,當(dāng)調(diào)用那幾個(gè)函數(shù)時(shí),才生成一個(gè)。
暫時(shí)把這個(gè)過程命名為Create On Call(COC)。
COC的好處是顯而易見的,每個(gè)對(duì)象將只有8字節(jié),虛表指針+數(shù)據(jù)對(duì)象的指針,“數(shù)據(jù)對(duì)象”是實(shí)際調(diào)用時(shí)才生成的對(duì)象,包括參數(shù)vector容器、回調(diào)函數(shù)指針(可能由動(dòng)態(tài)生成一個(gè)委托對(duì)象,以適應(yīng)廣泛類型的回調(diào)函數(shù))、對(duì)象鎖(防止干擾到前一個(gè)調(diào)用)。初始化成本接近0(虛函數(shù)表的初始化忽略不計(jì))。
當(dāng)調(diào)用operator()或async_call時(shí)(以下簡稱CALL),將調(diào)用create_parameters虛函數(shù),動(dòng)態(tài)生成一個(gè)vector。這樣,沒有調(diào)用到的Method不會(huì)象原來一樣影響到服務(wù)對(duì)象的構(gòu)建性能。
這就要求把Method的“元”信息提到全局,當(dāng)然更符合“元”的本意,原來由服務(wù)對(duì)象查詢Method以獲得“元”信息的過程,現(xiàn)在看來也是不合理的。
3、in模板可以省略。in是默認(rèn)的參數(shù)類型,返回值則默認(rèn)為out類型,這都是不需要明確指定的。
解決辦法:
這個(gè)問題是比較好解決的,在InOutTypeTraits模板類中,為各個(gè)偏特化版本定義一個(gè)type類型,InOutTypeTraits<T>::type的類型為in<T>,InOutTypes<in<T>>::type的類型為in<T>,InOutTypes<inout<T>>::type的類型為inout<T>,InOutTypes<o(jì)ut<T>>::type的類型為out<T>,InList模板類中進(jìn)行這種轉(zhuǎn)換。
4、異步調(diào)用隊(duì)列。在第2點(diǎn)中介紹道:
每個(gè)對(duì)象將只有8字節(jié),虛表指針+數(shù)據(jù)對(duì)象的指針,“數(shù)據(jù)對(duì)象”是實(shí)際調(diào)用時(shí)才生成的對(duì)象,包括參數(shù)vector容器、回調(diào)函數(shù)指針(可能由動(dòng)態(tài)生成一個(gè)委托對(duì)象,以適應(yīng)廣泛類型的回調(diào)函數(shù))、對(duì)象鎖(防止干擾到前一個(gè)調(diào)用)。初始化成本接近0(虛函數(shù)表的初始化忽略不計(jì))。
提到了對(duì)象鎖,這是一種低效的做法,可以使用異步調(diào)用隊(duì)列來替代它。
解決辦法:當(dāng)開始一個(gè)調(diào)用時(shí),臨時(shí)生成上面所說的“數(shù)據(jù)對(duì)象”,交由一個(gè)調(diào)用隊(duì)列去完成。這時(shí),由于Method對(duì)象基本不管理數(shù)據(jù),所以它成了一個(gè)空殼,作用是保存類型信息。
異步調(diào)用最好的實(shí)現(xiàn)就是整個(gè)系統(tǒng)都由異步調(diào)用構(gòu)成,而同步調(diào)用是由異步調(diào)用模擬而成。原本打算繞過這種方式,用最簡單的方法來做,現(xiàn)在好像又繞回來了。
上面這個(gè)做法,很好地把元信息和真實(shí)數(shù)據(jù)分開了,所以打算改成這種結(jié)構(gòu)。
5、全局元信息。
通過第4條的研究,已經(jīng)使得Method對(duì)象成為一個(gè)空殼,而“數(shù)據(jù)對(duì)象”在沒有調(diào)用時(shí)又不生成,使得自省結(jié)構(gòu)必須重新做。
考察了java等語言的自省,也打算把元信息的位置提升到全局,而每個(gè)Method對(duì)象將只保留一個(gè)全局元信息的指針,這樣應(yīng)該更自然。
(以后遇到的問題只更新到這個(gè)文檔中)