2009年2月16日 星期一

Web Game: 該lock全部或是部份的table

*以下是個人寫Web Game中途產生的心得。
很有可能不適用於其他類型的應用程式,請注意。

話說從頭


包括Web Game在內的多人網路遊戲都需要對資料庫或檔案進行鎖定(lock)。
鎖定的目的我原本寫了個範例出來,不過這樣這篇文章會太長所以算了吧。
抽象一點的舉例,就像是在白板上留言,要一個人寫完才能輪別人,否則留言就會看不懂。
多人遊戲時大家也得排隊輪著讀寫資料庫(雖然這動作時間很短所以看起來像大家同時)。

今天要講的是,一次該鎖定多少?

##ReadMore##

資料庫通常會起碼提供你一次最低可鎖定到一個table。
假設現在有三個table分別代表角色(char),地區(area)跟組隊(team)。
你可以鎖定它們其中之一,其中兩個或全部。

直覺的想法是,需要幾個就鎖定幾個。
如果自己暫時不會用到,就給別人用啊。
假設A鎖定了char跟area,B鎖定了team。
A跟B就可以同時動作而不會互斥。
效率比雙方都一次全部鎖定,B要等A做完要來的好。

理論上如此,而且其他應用程式很可能是對的,但遊戲不是。

因為沒有漸進式鎖定


首先原因是,我不確定其他資料庫,不過Mysql的lock是一次性的。
你不能先lock char,然後跟資料庫講我要多lock area。
這樣做會把char解鎖才去鎖定area,而不是你所想的鎖定了兩個table。

事實上這是很合理的,想一想下面這個情況:
A鎖定了char跟area而B鎖定了team。
A想要多鎖定team,B想要多鎖定char。
要不就雙方都拿不到(因為在對方那邊,而且對方不會放手),
要不就資料庫提供更複雜的機制解決這問題。

所以你不能漸進式鎖定。你在發出lock指令時就得指定好所有的table。

可是寫遊戲,通常資料庫存取動作並沒有那麼單純。
要在開頭就完全確定這裡只會用到某些table是很困難的。
有可能今天你要加某個功能,所以這個角色動作就得多使用到一個table。

更糟一點的狀況是,那個功能隱藏在好幾層函式呼叫的下面。
你得一層一層爬上去,找到到底誰呼叫了那個函式。
如果你每次做這個動作就得往上爬個四層尋找會呼叫它的一百個地方,
改個幾次你大概就投降了。

效率問題?


更重要的一點是,全部一次鎖定其實也沒什麼效率問題。

這邊的重點是,這是遊戲,而且還是Web Game。
遊戲的重點是玩家的角色。Web Game的動作則都是由玩家觸發的。
也就是說,90%以上的鎖定都一定會包括角色(char)的table
既然大家都要用到同一個table,那部份鎖定跟全部鎖定是一樣的
-不管怎樣都要排隊。

而且一次全部鎖定,也可以讓你不用去思索什麼時候該開始鎖定-
每個指令執行期間全部鎖起來就對了。
不用去看哪些動作有用到資料庫哪些沒有,省掉coding時考慮這些的麻煩,
可以更直接而輕鬆的使用資料庫。

所以我的建議是,如果你是要寫遊戲的話,就全部鎖定吧。
coding會方便很多,又不會真的犧牲多少效率。

沒有留言: