雖然.NET框架提供一些池的物件,但在套用時有時也不想參照其他庫時就需要自己編寫一些簡單的物件池。由於在編寫物件池的時候需要考慮到執行緒安全,一般在設計時使用非執行緒安全結構和加鎖來處理或使用System.Collections.Concurrent來解決執行緒安全的問題。顯然 System.Collections.Concurrent更多使用更輕量的自旋鎖來處理並行問題,看上去似乎比傳統的Lock方式有著更好的效能優勢!
不過最近在最佳化BeetleX的新版時讓我發現另一種 Lock的使用方式似乎有著更好的處理效果。在翻閱ArrayPool<T>的程式碼時候發現內部實作就是簡單粗暴的方式LOCK+數據組來實作一個高效的執行緒安全Stack結構。而裏面完全沒有使用.Net內建的Stack和ConcurrentStack結構。雖然程式碼使用了Lock處理,但程式碼使用了一些特別設計來解決多執行緒並行時由Lock引發的效能問題。實作過程中 ArrayPool<T>還進行了內部儲存分區,然後透過Thread.GetCurrentProcessorId()來確定操作區降低多執行緒並行時Lock帶來的效能問題。
透過以上思想Beetlex內部的物件分別使用了分區Stack+ Lock和
ConcurrentStack的設計,發現兩者測試下來的效能基本一致,但程式記憶體占有則有著巨大的差異!由於
ConcurrentStack內部有相應的結構產生在高並行時候會生產非常多的記憶體開銷和回收。而使用
分
區
Stac
k側記憶體開銷非常平穩!
以下是測試結果情況
分 區 Stac k
internal classPartition
{
private Stack<MemoryBlock> mData = new Stack<MemoryBlock>();
publiclong Length => mData.Count;
public MemoryBlock Pop()
{
lock (this)
{
if (mData.Count > 0)
return mData.Pop();
returnnull;
}
}
publicvoidPush(MemoryBlock data)
{
lock (this)
{
mData.Push(data);
}
}
}
分區ConcurrentStack
internal classPartition
{
private System.Collections.Concurrent.ConcurrentStack<MemoryBlock> mData = new System.Collections.Concurrent.ConcurrentStack<MemoryBlock>();
publiclong Length => mData.Count;
public MemoryBlock Pop()
{
mData.TryPop(outvar result);
return result;
}
publicvoidPush(MemoryBlock data)
{
mData.Push(data);
}
}
BeetleX
開源跨平台通訊框架(支持TLS)
提供HTTP,Websocket,MQTT,Redis,RPC和服務閘道器開源元件
個人微信:henryfan128 QQ:28304340
關註公眾號
https://github.com/beetlex-io/