Framework組最近的工作報告[Sumtec]

來源:互聯網
上載者:User
最近的工作有:
1、研究delegate對於效能的影響;
2、研究對象處理方式;
3、思考對象計算問題。

下面分別展開敘述:
一、delegate的問題。
這個問題是因為考慮到遊戲對象裡面有很多需要互動的地方,那麼到底如何進行互動就是一件值得探討的問題了。首先,遊戲互動總會有被動調用對象的情況發生,比如說對方打擊了“你”一下,那麼“你”就必須有相應的動作表現。那麼我們可以用“事件”的方式、“介面”的方式或者用“直接調用”的方式解決。我這裡不作詳細的報告了,簡單說一下實驗的結果和最後的結論,詳細的報告可以看我的另外一篇Post,或者這一篇Post有後繼的一些想法。簡單的說就是:一、delegate、interface以及directcall三種方式在單觸發的情況下,效能相差比較小。二、在多觸發的情況下delegate和其他方法的效能像差比較大,相差好幾倍。三、在觸發的代碼裡麵包含了一個一千次的簡單累加迴圈的情況下進行多觸發,效能相差不大,大約為5%。測試的結果對於delegate不是非常有利,但是最後我們考慮到如下幾點,還是不得不採用了delegate(event):
1、考慮情況三,效能相差並不是非常明顯。在這裡我們進行的是千萬次層級的運算,效能相差大約0.5s。但這個僅僅是單純測試這個方面的問題,如果擺到真正的成品裡面,還會夾雜著大量其他運算,所以這個問題帶來的效能影響會更低,基本上不應該是瓶頸所在。
2、考慮到多觸發的情況下,無論使用interface還是directcall,都會給設計開發人員帶來一定程度的麻煩。甚至對於引擎的設計來說還會需要一些額外的代碼,而某些東西的實際上面可能還會有其他的不方便。光是為了實現多觸發,我們就可能需要做不少的額外工作了。
3、考慮情況一,這個情況(單觸發)應該是大部分的實際情形,因此我們很可能並不能夠從使用interface/directcall上面獲得預期的好處。那些預期的效能提升都是在多觸發的情況下作測試得出的。
4、考慮到日後可能移植到Whidbey底下,可能這一效能差異根本就不會存在了。(這方面似乎有訊息能夠暗示delegate的效能問題會有比較令人感到滿意的解決。)

二、對象處理方式
這個問題實際上說的是大量對象應該如何維護的問題。這個問題在很多關於設計遊戲的文章裡面都會提到,大部分都是建議自己維護一個很大的對象池,以此避免大量對象的構造工作。我開始也對這個說法抱有積極的看法,但是後來思考一下就會發現,這個工作在.NET裡面是由GC來完成的。(比如說.NET的對象並不需要析構,比如說.NET的堆都是進行了相應的維護的。) 如果我們自己再維護一個對象池,那麼很可能會有問題存在:1、我們的對象池效能可以和GC相比嗎?正確性和安全性呢?2、我們的對象池會干擾GC的正常工作?比如某些對象我們不放到自己的對象池裡面,由於這個對象池的存在佔用了大量的空間,反而可能產生這個不再對象池的對象效率異常的低下。甚至有可能由於這個對象池本身過於龐大,本身就存在效率問題(GC無法把其中的一部分放在速度較快的GEN0裡面,而只好全部放到比較大的GEN2裡面了,等等)。3、自己設計一個對象池,那麼整個的設計是否會比較麻煩呢?會不會造成最終遊戲開發人員的設計上的麻煩呢?

對於這個問題,我交給了mikespook來進行測試。我對於測試的要求是這樣的:首先用大量的對象佔用大小為N的記憶體,這個步驟類比一些不會頻繁釋放的對象,作為基本的記憶體壓力。其次,用大小為x,數量為y的小對象,以頻率h在記憶體當中不斷的產生和銷毀,並且保證記憶體當中時刻有z個這樣的對象存在。在類比當中,N、x、y、h和z都應該是可以調整的,以期類比出不同情況下的結果,看一下在什麼樣的情況下交給GC比較快,在什麼樣的情況下自己做對象池比較合理,或者在什麼樣的情況下實際上沒有太大的差別。

最近mikespook自己在忙,可能沒有時間仔細做,甚至連報告也沒有時間給出來。昨天晚上他找到dudu,把結果簡單的說了一下,他大概簡單做了一下測試,結果表明至少GC比我們想象的要好。(我猜測這已經是相當保守的說法了,沒有和mike直接聊,不清楚具體的情況。我之所以這麼猜測的原因在下面這句話。)mike可能覺得這是因為對象池設計不良造成的,他找了一點資料,試圖再次做一個實驗,不過近期沒有時間,可能要等一段時間才有結果。事實上我已經預料到GC的效果比我們自己來做要好,但是沒有做過實驗不知道,不放心,現在我覺得我可以這麼說了:如果我們在.NET的架構下,能夠寫出一個比GC管理更有效對象池結構,那會令我非常吃驚的,估計微軟也會有點驚奇。原因是這樣的:MS對於GC的考慮可以說是非常的周詳,比Java的還要誇張。首先GC分為三代(Java是兩代),gen0的大小和CPU的lv1 cache一致,gen1和lv2的一致,gen2才是“無窮大”的,這裡的一致至少是數量級上面的。為什麼這麼分呢?因為一個研究表明,越老的對象就越不可能被釋放,同時也訪問的頻率也越低。反過來說就是最新產生的對象基本上都會在短期內被訪問到,而且通常是高頻率訪問。那麼如果訪問頻率高的對象總是放在同一塊記憶體當中,被CPU緩衝命中的可能性就越高!因為CPU總是試圖緩衝一段連續的,經常被訪問的記憶體塊。如果我們自己寫對象緩衝池,那麼就很難考慮得那麼仔細,那麼清楚。同時還很可能影響GC的發揮,因為一個對象長期存在(對象池存在的根本原因就是充分利用一個已經構造出來的對象,讓他長期存在),必然會被GC假設為訪問頻率低的對象,而很可能被轉移到Gen1甚至Gen2裡面去,效率就很可能會降低(經常緩衝不命中,需要從記憶體讀取)。此外,還可能佔用部分gen0的空間,使得一些不放在緩衝池進行處理的對象被迫轉移到Gen1或者Gen2裡面,不得不降低效率。而緩衝池還會佔用大量的堆空間,使得GC的記憶體配置變得困難。如果大家看過一些關於.NET下面開發高效率程式的建議的話,那麼應該看過這麼幾條:1、盡量少使用佔用大量空間的對象結構;2、盡量少的進行大量對象的關聯(就是我引用你,你引用他,他引用……這樣的一長串);3、……

當然,如果mike新的測試表明緩衝池比GC效率高的話,我還是不得不重新進行謹慎和仔細的考慮的。但是目前而言,我準備打算放棄“對象緩衝池”的想法了,準備進行下一步的設計和其他方面的實驗。

三、思考對象計算問題。
這個問題邏輯上比較簡單,但是要說明白還不是一件簡單的事情。假設你控制Tank,要“攻擊”一個我的Building,攻擊的結果根據你的Tank的攻擊力和我的Building的防禦力計算出傷害值,以此修正我的Building的HP值。好,問題馬上就出來了:你控制的Tank這個對象在哪裡呢?我的Building在哪裡呢?這個摧毀的動作怎麼進行計算——如何得到雙方的資料?計算在哪裡進行?修正如何進行?
詳細一點說,你要思考一下這樣的代碼怎麼具體的寫。首先說明一點,只要是網路遊戲,無論你是C/S模式還是分布式,無論是小規模對戰如C&C還是大規模遊戲如傳奇,都會存在的。比如說,我假設是C/S模式,又假設你採取的是server計算,然後把結果交給client,那麼這個計算的結果怎麼樣才能夠體現到client上面呢?是在網路上面傳輸給我(Building的控制者)“HP:-12”還是“Tank.ID=123; Action = Fire”?前一種方式下面,你打算怎麼實現一個架構?你總不能讓最終的遊戲設計著這麼設計一個遊戲對象吧:
Class MetalTank
{
   void OnReceivedMessage(string msg)
   {
      if (msg....) // parse the msg
   }
}
這麼做肯定沒有人喜歡,如果你說擺到引擎裡面的話,那麼必然需要使用reflection,因為引擎根本就不知道你有哪些對象,有哪些屬性。這樣的話效能不好不說,不美觀更是一個問題。當然,這麼設計最終肯定能夠運行起來,而能夠運行起來不應該是我們的目標。
好,如果說是後面那種方式,那麼Tank.ID=123的攻擊力我如何獲得?恩,難道我的機子上有Tank.ID=123的對象?假設有,那麼姑且不論這個Tank.ID=123的對象我怎麼獲得,下面這幾個問題我不得不提出來:
1、這個Tank.ID=123對象裡面哪一些屬性資料你需要知道?全部?還是部分?如何保持這些資料和對方機子上面的同步?如果全部資料你都有,那麼是不是就是說你的機子上面的對象和對方的是一樣的?雙方都在做相同的計算?那麼怎麼可能分散式運算呢?(每個用戶端都需要知道所有的資訊,都需要計算所有的東西)
2、如果不應該知道所有的東西,而應該只是知道有這麼一個對象以及一些基本的資訊,那麼是否意味著Tank這個類需要有兩個版本?(實際上前面那個server計算只把結果發送給client的模式裡面也有這個問題,server是一個完整的版本,而client是一個簡單的版本。)這樣的設計會不會很複雜?會不會增加了遊戲設計者的大量工作?哪一些資訊需要知道呢?哪一些不需要知道呢?萬一設計失誤把某些需要知道的弄成了不需要知道的,某些不需要知道的卻變成知道的,發現了這個Bug需要改,會不會造成整個遊戲的結構性調整呢?

寫這篇Post的時候我還以為把這個問題考慮清楚了,後來想想,發現還是沒有仔細考慮清楚,等我考慮清楚了再來報告。不過可以先透露一下,我還是堅持把計算放在Action這個類裡面,但是很可能會對這個類進行一個修改,把Action的步驟分開成多部分,甚至可能再添加一些輔助用的類。此外,我希望所有對象在每一個用戶端裡面都存在,但是並不都進行計算。(可是這樣的話又有一些其他問題出來了:我們很多時候是在計算的時候觸發引擎的一些更新,例如GUI上面的一些變化,比如位置、HP條等等,但是如果有一些對象只是接受結果,有一些對象會進行計算,那麼怎麼用比較統一的方式來觸發引清呢?)

看來需要思考的東西還有很多很多!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.