4

Lucian 在这里讨论了一种模式(提示 3:在返回任务的 API 中包装事件并等待它们)。

我正在尝试在一个经常调用的方法上实现它,该方法看起来像下面的人为代码:

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>

4

1 回答 1

6

无论您将采用哪种解决方案,如果您await每次调用此方法时都想要一个任务,那么创建一个新Task的任务是不可避免的,因为任务是不可重用的。最简单的方法是使用TaskCompletionSource.

因此,第一个选项比使用 a 更可取 IMO BufferBlock(不出所料,它会创建一个新TaskCompletionSource的 onReceiveAsync


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

public Task BlackBoxAsync() 
{
    return Task.Run(() => DoSomethingStuff());
}
于 2015-06-07T14:04:11.780 回答