使用TaskCompletionSource与BufferBlock <t>包装事件

时间:2015-06-07 13:57:48

标签: c# async-await task-parallel-library tpl-dataflow taskcompletionsource

卢西安在这里讨论了一种模式(Tip 3: Wrap events up in Task-returning APIs and await them)。

我试图在一个经常调用的方法上实现它,看起来像下面的设计代码:

public Task BlackBoxAsync() 
{ 
    var tcs = new TaskCompletionSource<Object>();  // new'ed up every call
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        { 
            DoSomethingStuff(); 
            tcs.SetResult(null); 
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

我担心每次通话TaskCompletionSource时都会有新的表现(我只说我每100毫秒调用一次这种方法)。

我当时正考虑使用BufferBlock<T>,认为每次通话都不会成为新手。所以它看起来像:

private readonly BufferBlock<object> signalDone; // dummy class-level variable, new'ed up once in CTOR

public Task BlackBoxAsync() 
{ 

    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        { 
            DoSomethingStuff(); 
            signalDone.Post(null);
        } 
        catch(Exception exc) {  } 
    }); 
    return signalDone.ReceiveAsync(); 
}

调用对象会将其称为:

for (var i=0; i<10000; i++) {
 await BlackBoxAsync().ConfigureAwait(false);
}

是否有人对使用BufferBlock<T>有任何想法?

1 个答案:

答案 0 :(得分:5)

无论您采用何种解决方案,如果您希望每次调用此方法时Password for user@SOMETHING.COM: 任务,创建新的await都是不可避免的,因为任务不可重复使用。最简单的方法是使用Task

所以第一个选项是IMO更喜欢使用TaskCompletionSource(不出所料,creates a new TaskCompletionSource on ReceiveAsync

更重要的是,您的代码似乎只是将工作卸载到BufferBlock并返回表示该工作的任务。你为什么不使用简单的ThreadPool

Task.Run