標籤:style color 使用 sp 資料 問題 bs 代碼 amp
任何多線程/並行/分布式都會面臨一個問題,“資料狀態共用"。
有經驗的開發人員會說,要想正確有效避開避開狀態共用,那麼就應該別用任何狀態共用。
雖然不得不說,這是一個不錯的建議,但是沒有狀態共用,你需要如何才能知道非本機資料的狀態?
也許你會說使用訊息,使用訊息來處理,那麼我們醜陋的回調金字塔應該疊的更高了。
不得不說這是一個解決辦法,但是為了保持狀態不被修改,那麼我們還得在遠程申請一個寫入鎖,防止資料被別的任務所修改。
那麼流程就是 申請鎖-》請求某個訊息狀態-》釋放鎖
假設我們一個簡單的交易任務,服務A上的玩家1準備和伺服器B上的玩家2準備交易。
玩家A需要付出100個金幣,玩家B需要把背包裡的一把刀給玩家A。
非分布式簡單非常簡單
if(玩家A.金幣>100 && 玩家B.擁有(刀)){
玩家A.金幣-=100;
玩家A.獲得(刀);
玩家B.失去(刀);
}
防止邏輯失敗,如果有個事務出錯後復原一下,這個邏輯就完美了,簡單有效.
那麼如果是分布式這就顯得比較麻煩了, 試著寫一個同步辦法,遠程調用比較費時間,但是至少能正常工作.
sv1.鎖定(玩家A)
sv2.鎖定(玩家B)
if(sv1.玩家A.金幣>100 && sv2.玩家B.擁有(刀)){
sv1.玩家A.金幣-=100;
sv2.玩家A.獲得(刀);
sv3.玩家B.失去(刀);
}
sv1.釋放(玩家A)
sv2.釋放(玩家B)
這個時候應該請出非同步來最佳化這次調用了..
sv1.鎖定(玩家A,(){
sv2.鎖定(玩家B,(){
if(sv1.玩家A.金幣>100 && sv2.玩家B.擁有(刀)){
sv1.玩家A.金幣(-100,(){
sv2.玩家A.獲得(刀,(){
sv3.玩家B.失去(刀,(){
sv1.釋放(玩家A,(){
sv2.釋放(玩家B,(){
});
});
);
});
});
}
})
});
我好想確定自己是不是來搞笑的..
如果保持之前設想的邏輯:
1.所有對單個對象執行都是單線程的.(資料訪問唯一)
2.當對象不在本地,提交到遠程執行,並返回結果.
3.獲得結果後,繼續在本地執行
交易發起會在玩家A這方發起,我們複製一個玩家B的鏡像,並且標記一個有效時間.
所有的修改都有操作標記.然後在玩家A和玩家B的邏輯都在玩家A線程上執行.
但是,因為我們操作的鏡像,並不影響原有資料.
操作完邏輯後,並不算成功,我們需要獲得操作完成後玩家A/B與交易之前的差異資料
如何獲得參考之前的一篇文章,然後到了我們真正要寫入的時候.
玩家A置等待鎖(也就是暫時不執行別的請求),遠程請求玩家B的寫入.
完成後,玩家A寫入. 釋放等待鎖.
寫入瞬間有一個防誤操作的鎖,其他時間都不影響其他任何操作.
如果遠程伺服器在交易發起的瞬間被,修改,那麼寫入失敗,只要丟棄雙方差異資料並釋放鎖即可.
從以上邏輯我們可以看出
1.資料訪問唯一讓我們無需擔心執行過程中被修改,也就是我們可以推算出任何非多步的操作都是成功的.(方法中不包含遠程方法,必然會執行成功)
2.線程切換機制,保證我們在編寫代碼時運行位置的正確性,因為你無需判斷是否需要遠程執行,僅僅都通過代理調用即可.
3.除非事務,保證雙方的操作必須成功,否則,無需任何鎖,也就是安全的跨服操作.
分布式非同步訊息架構構建筆記5——如何避開並行編程中的資料共用陷阱