2016-11-25 66 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中最受欢迎的功能,但它仍然适用于我们;) –