【问题标题】:Async CTP Bug - Task Never Completes异步 CTP 错误 - 任务永远不会完成
【发布时间】:2011-10-18 08:25:04
【问题描述】:

首先向前道歉:我无法将以下错误隔离到一个简单的控制台应用程序中。但是,在我比较简单的 ASP.NET Web Forms 应用程序中,下面的代码会导致当前线程无限期阻塞:

public class MyModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(System.Web.HttpApplication context)
    {
        context.BeginRequest += this.Context_BeginRequest;
    }

    private void Context_BeginRequest(object sender, EventArgs e)
    {
        Sleep().Wait();
        var x = 2; // This line is never hit.
    }

    private async Task Sleep()
    {
        await TaskEx.Run(() => System.Threading.Thread.Sleep(1000));
    }
}

任务状态保持为“WaitingForActivation”。有谁知道为什么会这样?

【问题讨论】:

  • 在控制台 exe 中运行良好;好像和asp.net有关

标签: c# .net asp.net task-parallel-library async-ctp


【解决方案1】:

编辑:Stephen Cleary 的评论提供了更多启示:

AspNetSynchronizationContext 是最奇怪的实现。它treats Post as synchronous rather than asynchronoususes a lock to execute its delegates one at a timeAspNetSynchronizationContext 不需要封送回同一个线程(但确实需要获取锁); Wait 的死锁是因为继续等待锁(由事件处理程序中的线程持有)


我的猜测是有一个SynchronizationContext 强制继续在与事件处理程序相同的线程上运行。您的事件处理程序正在阻塞该线程,因此延续永远不会运行,这意味着事件处理程序永远不会解除阻塞

这只是一个猜测 - 这是我目前唯一能想到的有意义的事情。

尝试解除阻止的一个选项是将您的Sleep 方法更改为:

private async Task Sleep()
{
    await TaskEx.Run(() => System.Threading.Thread.Sleep(1000))
                .ConfigureAwait(continueOnCapturedContext: false);
}

这将允许继续在不同的上下文中完成。

我很惊讶这样的同步上下文,请注意...我希望所有这些都发生在线程池上。可能BeginRequest 被稍微特殊对待了。

【讨论】:

  • 感谢您的深刻见解。将上面的“ConfigureAwait”添加到方法中可以解决示例问题。但是,真正的 async 方法实际上是较低级别程序集的一部分,其他组件也使用该程序集。您会建议我以这种方式修改我的所有库 TaskEx.Runs,还是有更好的方法来解决行为不端的调用代码(如本例中的 IHttpModule)?
  • @LawrenceWagerfield:说实话,目前还不清楚这里真正的行为不端——我怀疑每一点都有其意义。显然,在真正的代码中,您不只是想睡觉......如果您能提供更多关于您的真正代码正在尝试做什么的指示,我也许能够提供更多帮助。至于是否正常调用ConfigureAwait,Stephen Toub最近的帖子可能值得在这里阅读:msdn.microsoft.com/en-us/magazine/hh456402.aspx
  • 本例中的底层库代码相当简单;它只是引发一个事件,该事件由与数据库交互的 2 个操作处理。这个问题绝对是 IHttpModule 的问题;当从其他区域调用时,该代码工作正常。有没有办法覆盖 IHttpModule 使用的同步上下文?
  • @LawrenceWagerfield:我不知道 - 但在继续之前你需要完成所有事情吗?你可以直接await Sleep() 而不是打电话给Sleep.Wait() 吗? (换句话说,使事件处理程序也异步。)这样做的缺点是您的处理程序的其余部分可能会在其他事情开始发生之后执行
  • 感谢 Jon - 我认为现在的答案是不要在 IHttpModules 中使用 Wait(),而是让所有方法异步。我看不出这总是可行的,因为有时您需要与同步方法中的异步方法进行交互(考虑从异步库方法推断目标 URL 的 URL 重写模块 - 在这里将不可避免地等待,因为重写需要在 BeginRequest 事件完成之前发生)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多