等待任务永远不会完成,即使它的状态转换为 'RanToCompletion'

Awaiting a Task never completes even though its state transitions to 'RanToCompletion'

首先,抱歉 -- 我无法在适当简单的示例应用程序中重现此行为。此功能在对调用代码进行一些重构之前有效。

我正在尝试使用 TaskCompletionSource 来表示异步操作的结束(长 运行 进程完成,或者超时可能会使用 TrySetResult() 表示完成)。

我的问题是,尽管我可以看到任务正在从 "WaitingForActivation" 过渡到 "RanToCompletion",但对 await 的调用从未完成。

作为测试,我创建了一个任务延续,它正在被调用,我添加了一个计时器来显示任务状态:

async Task<Foo> WaitForResultOrTimeoutAsync()
{
        //... [Create 'pendingReq' with its TaskCompletion property]

        TaskCompletionSource<Foo> myCompletion = pendingReq.TaskCompletion;

        Task<Foo> theTask = myCompletion.Task;

        var taskContinuation = theTask.ContinueWith(resp =>
        {
            Console.WriteLine("The task completed");
            return resp.Result;
        });

        new Timer(state =>
        {
            Console.WriteLine("theTask TaskCompletion state is {0}", theTask.Status);
            Console.WriteLine("taskContinuation TaskCompletion state is {0}", taskContinuation.Status);
        }, null, 0, 1000);

        //var result = await theTask;
        var result = await taskContinuation;
        Console.WriteLine("We're FINISHED");    // NEVER GETS HERE
        return result;
}

这导致以下输出:

theTask TaskCompletion state is WaitingForActivation
taskContinuation TaskCompletion state is WaitingForActivation
theTask TaskCompletion state is WaitingForActivation
taskContinuation TaskCompletion state is WaitingForActivation
The task completed
theTask TaskCompletion state is RanToCompletion
taskContinuation TaskCompletion state is RanToCompletion
theTask TaskCompletion state is RanToCompletion
taskContinuation TaskCompletion state is RanToCompletion

当然随着继续被命中,直接等待任务也应该完成,不是吗?这种行为可能有哪些外部(调用)因素?

我很确定在调用堆栈更上层的某个时刻,调用代码阻塞了一个任务,并且这段代码是在同步上下文中执行的(即,在 UI 线程上或从ASP.NET 请求)。这将 cause a deadlock 我在我的博客上有完整的解释。最正确的解决方案是用 await.

替换阻塞(通常是 WaitResult 调用)

之所以ContinueWith没有被阻塞是因为它使用了当前的TaskScheduler而不是当前的SynchronizationContext,所以它可能最终在线程池上运行在这种情况下。如果我对调用代码阻塞的猜测是正确的,那么 ContinueWith 如果你传递给它一个 TaskScheduler.FromCurrentSynchronizationContext().

也会死锁