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