我对TaskCompletionSource有一个不寻常的问题让我感到困惑。一旦我调用TrySetResult,我有一个TaskCompletionSource等待任务完成。我在代码中的三个位置调用它:从WCF线程立即返回值到APM WCF BeginXXX EndXXX;从另一个WCF线程立即返回到APM;最后来自NServiceBus处理程序线程。
我从MS-PL提供的无处不在的ToAPM开始。 http://blogs.msdn.com/b/pfxteam/archive/2011/06/27/using-tasks-to-implement-the-apm-pattern.aspx
我注意到两个基于WCF的线程100%的时间都在工作。在100小时的硬测试中,还有大量的单元测试,我从来没有遇到过将完成的任务返回到AsyncCallback的单一故障。
从MS提供的ToAPM代码中,代码在已完成的任务上使用ContinueWith在启用计划的任务中调用AsyncCallback。
我还没解决的问题是NServiceBus线程在TaskCompletionSource对象上调用TrySetResult。我发现中断的时间,在未定义的时间段内,呼叫完全失败。我在调用和ContinueWith代码内部的代码中设置了断点。我总是在TrySetResult上获得断点,但有时只在ContinueWith代码中的代码上。
希望以下信息可以解释这个问题。
我使用带超时的CancellationTokenSource并设置结果以调用TaskCompletionSource obj上的TrySetResult。当上述调用无法将任务移至完成时,将触发超时代码。这个超时代码从来没有用过。它100%的成功。
有趣的是,在从NServiceBus线程调用TrySetResult的相同代码中,当它工作时,它就像调用TaskCompletionSource对象上的TrySetResult一样轻松调用取消对象的取消。 / p>
当一个人失败时他们都会失败。
然后经过不分青红皂白的时间再次发挥作用。
这是生产和QA环境中的WCF服务器,每个都显示相同的结果。
最奇怪的是,对于一个WCF连接,NServiceBus线程成功,另一个同时失败。然后有时两个都工作,然后都失败了。同样,所有这些都在同一时间。
我已经尝试过很多方法解决这个问题但无济于事:
我真的不知道还有什么可以尝试的。
我进行检查以确保TaskCompletionSource obj未完成,并且在中断期间它不是。 我进行了检查,以确保在停机期间取消CancellationTokenSource对象或取消暂停,但事实并非如此。
我检查了调试器中的对象,看起来很好。
他们只是不工作有时。
NserviceBus线程中是否存在不一致,有时会阻止调用工作? 我可以尝试一些线程封送吗?
我到处搜索,我没有看到提到这个问题。它有独特之处吗?
我完全感到困惑,需要一些想法。
答案 0 :(得分:1)
从NServiceBus线程执行中删除调用。使用QueueUserWorkItem等线程或旋转自己的线程隔离对TrySetResult的调用。由于执行恢复使用该线程,您可能需要一些额外的线程来处理吞吐量。以太网旋转多个专用线程或使用线程池。我测试了在专用线程中调用TrySetResult并且它们可以工作。
以下是演示单个专用线程的代码:
public static void Spin()
{
ClientThread = new Thread(new ThreadStart(() =>
{
while (true)
{
try
{
if (!HasSomething.WaitOne(1000, false))
continue;
while (true)
{
WaitingAsyncData entry = null;
lock (qlocker)
{
if (!Trigger.Any())
break;
entry = Trigger.Dequeue();
}
if (entry == null)
break;
entry.TrySetResult("string");
}
}
catch
{
}
}
}));
ClientThread.IsBackground = true;
ClientThread.Start();
}
这是ThreadPool示例代码:
ThreadPool.QueueUserWorkItem(delegate
{
entry.TrySetResult("string");
});
使用ThreadPool而不是静态线程可以提供更大的灵活性和可扩展性。