【问题标题】:Async Framework TaskEx.Delay issue异步框架 TaskEx.Delay 问题
【发布时间】:2011-06-02 17:11:36
【问题描述】:

我在 C# 中使用异步框架 CTP 调用 TaskEx.Delay 时发现了某种问题

public async Task<string> TestAsync() {
    return await TaskEx.RunEx<string>( async () => { //in real app this is time consuming code so this line is so complex 
            await TaskEx.Delay( 1000 );
            return "test;
        } );
}

public async void Test {
    var count = 0;
    while( count < 100 ) {
        var val = await TestAsync();
        Console.WriteLine( val ); // in real app this line adds elements to observable collection binded to ListBox
        count++;
    }
}

控制台上的输出大多出现一次(有时是两到三次),但不像我预期的那样出现 100 次。

编辑:

它不是控制台应用程序(上面的代码已简化)它是 WP7 应用程序。不使用延迟它可以正常工作。

【问题讨论】:

  • 这不是您正在运行的实际代码 - 您在非异步方法中等待。如果你能想出一个简短但完整的程序,那真的很有帮助。目前我无法使用编译器,但有了一个完整的应用程序,我至少可以有更多的机会来诊断正在发生的事情。
  • 如果您认为 TaskEx.Delay 有问题,请尝试在控制台应用程序中显示它。
  • 我很确定 - 从 Microsoft Visual Studio Async CTP 包中打开示例项目 (C# Windows Phone) Netflix。在 MainPage.xaml.cs 中的 LoadMoviesAsync 中添加 await TaskEd.Delay (1000),在 imageCount += movies.Length 正下方的 78 行附近;并将 pageCount 更改为 2 以更好地查看结果。启动应用程序在年份框中输入 2000 并上下移动列表中的项目。一段时间后,项目将停止加载,但仍有数百个。去掉Delay就没有问题了!

标签: c# frameworks asynchronous


【解决方案1】:

这是因为Test 方法确实是一个异步方法。 C# 编译器只是让您通过具有 void 返回类型来隐藏它。因此,如果您的主要方法如下所示

public static void Main() {
  Test();
}

那么它实际上并没有运行Test 并等待它完全完成。相反,它实际上是在安排 Test 运行,并且它的完成将在未来的某个时候发生。因此,您看到不同的输出是有道理的,因为它与时间相关。

【讨论】:

    【解决方案2】:

    这可能是因为您在控制台应用程序中运行,而不是 Windows 应用程序。

    异步在控制台应用程序中的行为与在 Windows 窗体、WPF 或 WCF 应用程序中的行为不同,因为没有同步上下文。因此,await 回发到线程池线程,实际上并没有“等待”执行。

    如果您在 WPF 或 Windows 窗体应用程序中运行它,它将按预期运行。


    附带说明,您的方法过于复杂。你可以这样做:

    public async Task<string> TestAsync() {
        await TaskEx.Delay( 1000 );
        return "test";
    }
    

    这将有效地以与您之前的方法相同的方式工作,但开销要少得多(并且更简单)。

    【讨论】:

    • 我认为说“异步在控制台应用程序中不能按预期工作”是一种误导,因为这显然取决于您的期望。 Async 的工作方式完全符合 在控制台应用程序中的预期,这是我进行大部分测试的地方 :) 示例代码目前不完整,但可以在控制台中以合理的方式轻松运行应用程序。
    • @Jon:控制台模式应用程序中的异步和等待行为与 Windows 窗体、WPF、WCF 等应用程序中的行为截然不同(当然,除非您安装了自定义同步上下文) .随着线程同步和许多问题的出现,发生的事情的正常指导发生了巨大的变化。是的,使用异步编写一个合理的控制台模式应用程序是完全可能的,但它需要你真正注意你在做什么。
    • 是的。在控制台应用程序中执行此操作实际上非常容易 - 您需要做的就是永远等待(直到您感到无聊)或等待从异步方法返回的任务。但是,是的,它是不同的。我还没有查看 WCF 服务的行为方式 - 我希望它是线程敏捷的,即使用线程池 - 但我还没有对其进行测试。能够编写不关心每个步骤在哪个线程上运行的服务器端代码当然是很好
    • @Jon:WCF 将同步上下文安装到调用中,因此它的行为更像 Windows 窗体。默认情况下,每个服务调用都在它自己的线程上运行(具有自己的上下文),因此效果很好,您不必担心线程同步。如果您更改服务的并发模式,这可能会有所不同,但这是默认行为。
    猜你喜欢
    • 1970-01-01
    • 2016-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-21
    • 2015-02-24
    • 1970-01-01
    • 2014-03-27
    相关资源
    最近更新 更多