[英]Refactoring code with a lot of “locks” to more lock-free code
更多感謝Matthew Watson注意到並注意到我打算將我的代碼移植到c ++ - linux所以我更喜歡“平台無關”的代碼
我的交易應用程序幾乎無鎖。 下面的代碼是我唯一使用鎖的地方。 讓我從代碼開始,它很長但不要擔心有很多重復部分,所以它很簡單。 我更喜歡添加所有“重復”部分,以更好地展示我的工作方式:
Task.Factory.StartNew(() =>
{
while (true)
{
Iterate();
}
}, TaskCreationOptions.LongRunning);
private void Iterate()
{
bool marketDataUpdated = false;
lock (ordersToRegisterLock)
{
if (ordersToRegister.Count > 0)
{
marketDataUpdated = true;
while (ordersToRegister.Count > 0)
{
Order order = ordersToRegister.Dequeue();
// Stage1, Process
}
}
}
lock (aggrUpdatesLock)
{
if (aggrUpdates.Count > 0)
{
marketDataUpdated = true;
while (!aggrUpdates.IsNullOrEmpty())
{
var entry = aggrUpdates.Dequeue();
// Stage1, Process
}
}
}
lock (commonUpdatesLock)
{
if (commonUpdates.Count > 0)
{
marketDataUpdated = true;
while (!commonUpdates.IsNullOrEmpty())
{
var entry = commonUpdates.Dequeue();
// Stage1, Process
}
}
}
lock (infoUpdatesLock)
{
if (infoUpdates.Count > 0)
{
marketDataUpdated = true;
while (!infoUpdates.IsNullOrEmpty())
{
var entry = infoUpdates.Dequeue();
// Stage1, Process
}
}
}
lock (tradeUpdatesLock)
{
if (tradeUpdates.Count > 0)
{
marketDataUpdated = true;
while (!tradeUpdates.IsNullOrEmpty())
{
var entry = tradeUpdates.Dequeue();
// Stage1, Process
}
}
}
if (marketDataUpdated)
{
// Stage2 !
// make a lot of work. expensive operation. recalculate strategies, place orders etc.
}
}
private readonly Queue<Order> ordersToRegister = new Queue<Order>();
private readonly object ordersToRegisterLock = new object();
private readonly Queue<AggrEntry> aggrUpdates = new Queue<AggrEntry>();
private readonly object aggrUpdatesLock = new object();
private readonly Queue<CommonEntry> commonUpdates = new Queue<CommonEntry>();
private readonly object commonUpdatesLock = new object();
private readonly Queue<InfoEntry> infoUpdates = new Queue<InfoEntry>();
private readonly object infoUpdatesLock = new object();
private readonly Queue<TradeEntry> tradeUpdates = new Queue<TradeEntry>();
private readonly object tradeUpdatesLock = new object();
public void RegistorOrder(object sender, Gate.RegisterOrderArgs e)
{
lock (ordersToRegisterLock)
{
ordersToRegister.Enqueue(e.order);
}
}
public void TradeUpdated(object sender, Gate.TradeArgs e)
{
lock (tradeUpdatesLock)
{
foreach (var entry in e.entries)
{
tradeUpdates.Enqueue(entry);
}
}
}
public void InfoUpdated(object sender, Gate.InfoArgs e)
{
lock (infoUpdatesLock)
{
foreach (var entry in e.entries)
{
infoUpdates.Enqueue(entry);
}
}
}
public void CommonUpdated(object sender, Gate.CommonArgs e)
{
lock (commonUpdatesLock)
{
foreach (var entry in e.entries)
{
commonUpdates.Enqueue(entry);
}
}
}
public void AggrUpdated(object sender, Gate.AggrArgs e)
{
lock (aggrUpdatesLock)
{
foreach (var entry in e.entries)
{
aggrUpdates.Enqueue(entry);
}
}
}
在我的代碼中,我有兩個階段。 Stage1
是更新階段, Stage2
處於工作階段。 我需要盡快在這兩個階段之間切換,如下所示:
Stage2
Stage2
Stage2
在Stage2
我不應該更新,但應該保持“收集”更新,以便我可以在以后應用它們。
重要的是 - 這是非常關鍵的延遲代碼,因此我同意“花費”一個核心以獲得最小的延遲! 因此,當發生任何更新時,我需要盡快處理它並執行Stage2
。
所以我希望現在很清楚我需要實現什么,而且很清楚我是如何實現的。 現在是討論我的代碼有多好的時候了。 我確實看到了幾個潛在的問題:
歡迎提出任何有關如何改進我寫作的建議,謝謝!
upd部分解決了 - 據我所知,我最好將查詢替換為無鎖(可能是基於環緩沖的?)查詢。我想我稍后會使用c ++版本的disruptor。 我也使用了這篇文章http://www.umbraworks.net/bl0g/rebuildall/2010/03/08/Running_NET_threads_on_selected_processor_cores並用“固定”核心上運行的線程替換了任務,但是我還在使用“忙” -spin“,可能我應該使用更聰明的東西?
使用下面的代碼,您在“階段1”處理期間不再被鎖定:
Task.Factory.StartNew(() =>
{
while (true)
{
Iterate();
}
}, TaskCreationOptions.LongRunning);
private void Iterate()
{
bool marketDataUpdated = false;
foreach (Order order in ordersToRegister)
{
marketDataUpdated = true;
// Stage1, Process
}
foreach (var entry in aggrUpdates)
{
marketDataUpdated = true;
// Stage1, Process
}
foreach (var entry in commonUpdates)
{
marketDataUpdated = true;
// Stage1, Process
}
foreach (var entry in infoUpdates)
{
marketDataUpdated = true;
// Stage1, Process
}
foreach (var entry in tradeUpdates)
{
marketDataUpdated = true;
// Stage1, Process
}
if (marketDataUpdated)
{
// Stage2 !
// make a lot of work. expensive operation. recalculate strategies, place orders etc.
}
}
private readonly ConcurrentQueue<Order> ordersToRegister = new ConcurrentQueue<Order>();
private readonly ConcurrentQueue<AggrEntry> aggrUpdates = new ConcurrentQueue<AggrEntry>();
private readonly ConcurrentQueue<CommonEntry> commonUpdates = new ConcurrentQueue<CommonEntry>();
private readonly ConcurrentQueue<InfoEntry> infoUpdates = new ConcurrentQueue<InfoEntry>();
private readonly ConcurrentQueue<TradeEntry> tradeUpdates = new ConcurrentQueue<TradeEntry>();
public void RegistorOrder(object sender, Gate.RegisterOrderArgs e)
{
ordersToRegister.Enqueue(e.order);
}
public void TradeUpdated(object sender, Gate.TradeArgs e)
{
foreach (var entry in e.entries)
{
tradeUpdates.Enqueue(entry);
}
}
public void InfoUpdated(object sender, Gate.InfoArgs e)
{
foreach (var entry in e.entries)
{
infoUpdates.Enqueue(entry);
}
}
public void CommonUpdated(object sender, Gate.CommonArgs e)
{
foreach (var entry in e.entries)
{
commonUpdates.Enqueue(entry);
}
}
public void AggrUpdated(object sender, Gate.AggrArgs e)
{
foreach (var entry in e.entries)
{
aggrUpdates.Enqueue(entry);
}
}
這是一種可能更便攜的方法。 希望能幫助到你。
public class SafeQueue<T> : Queue<T>
{
public T SafeDequeue()
{
lock (this)
{
return (Count > 0) ? Dequeue() : null;
}
}
public void SafeEnqueue(T entry)
{
lock (this)
{
Enqueue(entry);
}
}
}
Task.Factory.StartNew(() =>
{
while (true)
{
Iterate();
}
}, TaskCreationOptions.LongRunning);
private void Iterate()
{
bool marketDataUpdated = false;
while ((Order order = ordersToRegister.SafeDequeue()) != null)
{
marketDataUpdated = true;
// Stage1, Process
}
while ((var entry = aggrUpdates.SafeDequeue()) != null)
{
marketDataUpdated = true;
// Stage1, Process
}
while ((var entry = commonUpdates.SafeDequeue()) != null)
{
marketDataUpdated = true;
// Stage1, Process
}
while ((var entry = infoUpdates.SafeDequeue()) != null)
{
marketDataUpdated = true;
// Stage1, Process
}
while ((var entry = tradeUpdates.SafeDequeue()) != null)
{
marketDataUpdated = true;
// Stage1, Process
}
if (marketDataUpdated)
{
// Stage2 !
// make a lot of work. expensive operation. recalculate strategies, place orders etc.
}
}
private readonly SafeQueue<Order> ordersToRegister = new SafeQueue<Order>();
private readonly SafeQueue<AggrEntry> aggrUpdates = new SafeQueue<AggrEntry>();
private readonly SafeQueue<CommonEntry> commonUpdates = new SafeQueue<CommonEntry>();
private readonly SafeQueue<InfoEntry> infoUpdates = new SafeQueue<InfoEntry>();
private readonly SafeQueue<TradeEntry> tradeUpdates = new SafeQueue<TradeEntry>();
public void RegistorOrder(object sender, Gate.RegisterOrderArgs e)
{
ordersToRegister.SafeEnqueue(e.order);
}
public void TradeUpdated(object sender, Gate.TradeArgs e)
{
foreach (var entry in e.entries)
{
tradeUpdates.SafeEnqueue(entry);
}
}
public void InfoUpdated(object sender, Gate.InfoArgs e)
{
foreach (var entry in e.entries)
{
infoUpdates.SafeEnqueue(entry);
}
}
public void CommonUpdated(object sender, Gate.CommonArgs e)
{
foreach (var entry in e.entries)
{
commonUpdates.SafeEnqueue(entry);
}
}
public void AggrUpdated(object sender, Gate.AggrArgs e)
{
foreach (var entry in e.entries)
{
aggrUpdates.SafeEnqueue(entry);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.