List存了若干個物件,通過多執行緒長連接Socket的高并發心跳包更新物件狀態(每個物件一個Socket,分別更新),經常需要Find或者FindAll或者for回圈等進行修改物件操作物件,偶爾有List的ADD,Remove等操作,哪些地方需要lock?
uj5u.com熱心網友回復:
多執行緒修改同一個物件的不同屬性uj5u.com熱心網友回復:
List不適合這種情況。用Dictionary資料結構,比如ConcurrentDictionary。
uj5u.com熱心網友回復:
假如只能用List呢
uj5u.com熱心網友回復:
接收到更新放入佇列ConcurrentQueue再進行處理uj5u.com熱心網友回復:
只用list,基本都要加鎖,Find其實也是在for回圈uj5u.com熱心網友回復:
增刪改,每個動作都要加鎖uj5u.com熱心網友回復:
System.Collections.Concurrent 這里面有幾個執行緒安全的集合uj5u.com熱心網友回復:
先脫離你的限定,直接從你的原始需求聊心跳對應session--------在通行的IT世界里session用啥呢?當然第一眼就是快取
你的要求可以是Cache,微軟給你的MemoryCache就是執行緒安全的,同時你也可省掉一些操作(比如延長生存時間,自動移除過期)
uj5u.com熱心網友回復:
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/lock-statementuj5u.com熱心網友回復:
msdn已經給你推薦了 執行緒安全集合?ConcurrentQueue
?ConcurrentStack
?ConcurrentBag :
?BlockingCollection :
?ConcurrentDictionary
你自己選擇就好了。
至于一定要用list,那么就自己Lock
uj5u.com熱心網友回復:
就是這些操作需要lock,例如
lock(myList)這類底層操作需要整體 lock。
return FindAll(myList, .......);
uj5u.com熱心網友回復:
修改佇列中某一個物件的屬性,不是 lock 佇列,而是 lock 找到的物件。
uj5u.com熱心網友回復:
凡是需要原子操作的,都加上lock
uj5u.com熱心網友回復:
lock 是個性能瓶頸,所以通常要盡可能對“細節”進行同步,而不是過多從高層對大物件進行死鎖。因此并發多執行緒設計方面更加體現了一種“哲學思維”方式,也就是注重實證的方式、通過系統自測來確定“相對的”是非概念,而不是基于外來的所謂概念來評判絕對的是非概念。通常我們都會寫一些測驗,例如Task[] tasks = ........;而且每天會重復幾百遍,比如說你中午吃飯的時候就可以讓幾十個測驗用例重復實體化、且并行運行幾萬個測驗,然后看最后的斷言是否能發現是一億分之一的資料不一致性。
await Task.WhenAll(tasks);
Debug.Assert(checkResults(),"系統并發操作例外“);
編程絕不是靠別人灌輸什么“理論”而決定設計的好壞。要靠自己長期寫測驗。
uj5u.com熱心網友回復:
用ConcurrentDictionary就行了uj5u.com熱心網友回復:
還有個問題,就是假如為了性能都不做lock,會產生什么錯誤和后果?(可以接受臟讀,基本沒有同時操作同一個物件的時候,ADDRemove的概率也很小,假如報錯try、catch能捕獲也行,只要不把系統弄崩潰就行)
uj5u.com熱心網友回復:
謝謝各位
uj5u.com熱心網友回復:
...就是假如為了性能...
List資料結構的Find,Remove的復雜度是O(n),而Dictionary資料結構的復雜度是O(1)。
過于簡單的說,當你有2000個連接,Find,Remove操作Dictionary的演算法效率高2000倍。
uj5u.com熱心網友回復:
從性能開銷來說,加鎖本身很快。當出現競態時,性能才'大幅'下降(這里的'大幅'是相對非競態加鎖而言)。比如List移除一個元素,List需要把目標元素移除后,把后續資料都往前挪一個位置。
對此類操作,加鎖的程序就會相對的長,更容易招致出現競態(即多個操作爭相下鎖,互相競爭)。
uj5u.com熱心網友回復:
你要做到資料同步的效果就可以了,不能夠出現洗掉后找不到這個物件,或是Null的問題轉載請註明出處,本文鏈接:https://www.uj5u.com/net/29656.html
標籤:C#
