当我的任务从自定义TaskScheduler启动时,'await'不会返回

BTo*_*TKD 6 .net c# asynchronous task task-parallel-library

背景:

我有一个"信使"课.它发送消息.但是由于限制,我们说它一次只能发送 - 最多 - 5条消息.

我有一个WPF应用程序,它根据需要对消息进行排队,并在继续之前等待处理排队的消息.由于应用程序的异步性质,可以await在任何给定时间编辑任意数量的消息.

目前的实施:

为此,我Task<Result> SendMessage(Message message)在我的消息类中实现了一个API.消息传递类的内部是一个自定义的TaskScheduler(来自MSDNLimitedConcurrencyTaskScheduler),其并发级别设置为5.这样,我希望无论排队多少消息,一次只发送5个,我的客户端应用程序将耐心等待,直到其相应的消息已被处理.

问题:

当我awaitSendMessage方法,我可以通过调试器看到消息已完成并返回结果,但我的代码永远不会执行awaited方法调用!

await在使用不同的TaskScheduler计划的任务时,是否需要进行一些特殊注意事项?

剪切代码:

从我的客户/消费功能:

public async Task Frobulate()
{
    Message myMessage = new Message(x, y, z);
    await messenger.SendMessage(myMessage);

    //Code down here never executes!
}
Run Code Online (Sandbox Code Playgroud)

从我的使者班:

private TaskScheduler _messengerTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(5);
private TaskFactory _messengerTaskFactory = new TaskFactory(_messengerScheduler);

public Task<Result> SendMessage(Message message)
{
    //My debugger has verified that "InternalSendMessage" has completed, 
    //but the caller's continuation appears to never execute
    return _messengerTaskFactory.StartNew(() => InternalSendMessage(message));
}
Run Code Online (Sandbox Code Playgroud)

更新:

"冻结"实际上并不是由我的习惯引起的TaskScheduler; 当我Task使用默认排队时TaskFactory,会发生相同的行为!必须在更基础的层面上发生其他事情,可能是由于我自己的愚蠢.

i3a*_*non 3

根据评论,您可能会遇到死锁,因为您阻塞了异步代码。

SynchronizationContext使用 async 时,只要对or存在线程限制,并且使用or 的TaskScheduler代码块就有可能出现死锁。异步操作需要一个线程来完成执行,但它无法获得该线程,因为(或在您的情况下)正在等待相同的操作完成,然后才允许“新”操作运行。Task.ResultTask.WaitSynchronizationContextTaskScheduler

深入了解 Stephen Cleary 的博客文章:不要阻止异步代码