2016-11-25 60 views
1

在我的ASP.NET API中,我收到了一系列要保留的消息。在這種特殊情況下,API的響應性取代了任何單個消息的重要性,所以我不是直接寫入數據存儲,而是將傳入消息推送到隊列並在後臺線程上儘快處理它們。使用帶有隊列和後臺線程的TaskCompletionSource

在某些情況下,我可能有一個需要確認的寫操作的成功或失敗,所以我在使用下面的代碼定製MessageContext的對象纏上了我的消息:

public class WriteMessageContext 
{ 
    public Message Message { get; private set; } 
    TaskCompletionSource<bool> complete = new TaskCompletionSource<bool>(); 

    public WriteMessageContext(Message message) 
    { 
     Message = message; 
    } 

    public Task<bool> WaitForInsert() 
    { 
     return complete.Task; 
    } 

    public void Success() 
    { 
     complete.SetResult(true); 
    } 

    public void Error() 
    { 
     complete.SetResult(false); 
    } 
} 

成功和錯誤方法旨在由在後臺處理每個排隊消息的工作線程調用。然後,在我的控制,我可以這樣做:

var ctx = new WriteMessageContext(msg); 
queue.Enqueue(ctx); 

// optionally... 
if (await ctx.WaitForIt()) { 
    // successful 
} else { 
    // or not 
} 

這是一個合適的使用TaskCompletionSource的+異步/等待,還是我用wreckless放棄bastardizing呢?是否有任何潛在的問題我應該關注這樣做?

+1

我會推薦使用'TaskCreationOptions.RunContinuationsAsynchronously'和'TaskCreationOptions.DenyChildAttach'標誌。 –

回答

1

對我來說,這是TaskCompletionSource<T>的有效用法。

順便說一句,也許你會感到驚訝,因爲任務並行庫(TPL)中有一些隱藏的功能/寶石,稱爲data-flow blocks

其實,還有一個能滿足您的要求:BufferBlock<T>

BufferBlock<T>類表示通用異步消息傳遞結構。該類存儲消息的先進先出(FIFO)隊列,可以由多個源寫入或由多個目標讀取。當目標收到來自BufferBlock<T>對象的消息時,該消息將從消息隊列中刪除。因此,雖然BufferBlock<T>對象可以有多個目標,但只有一個目標會收到每條消息。如果要將多個消息傳遞給另一個組件,並且該組件必須接收每個消息,則BufferBlock<T>類很有用。

+0

甚至不知道存在。我應該使用它,而不是像現在一樣輪詢ConcurrentQueue 。 – Chris

+0

@Chris是的,它不是.NET中最受歡迎的功能,但它仍然適用於我們;) –