如何以正确的方式实现我的异步方法?

时间:2012-12-11 10:09:44

标签: c# async-await c#-5.0

我想知道实现自己的异步方法的最佳方法是什么。我已经阅读了this article并且它说将同步方法包装到任务中并将其用作异步方法并不是一个好主意,因为这种方式使用其他线程并使用更多资源,这就是我们想要避免的使用异步。

在文章中使用TaskCompletionSource,但我并不确切知道如何使用它。 TaskCompletionSource的目的是什么?

2 个答案:

答案 0 :(得分:4)

编写async方法的最佳资源是Task-based Asynchronous Pattern (TAP) document by Stephen Toub。该文件中的大部分信息现在都是part of the official MSDN documentation

如果你想要一个更短(但仍然彻底)的教程,我推荐自己的async/await intro blog post,还有其他一些教程。一旦你学会了async,下一个好资源就是official async/await FAQ

Channel9上还有很多很棒的async视频。当它们仍然是CTP时,许多(大多数?)讨论async,但在投入生产时很少进行设计更改。

要回答您的具体问题,TaskCompletionSource用于围绕现有异步操作(例如,I / O操作,计时器或事件)创建Task包装器。您无法在Task创建的TaskCompletionSource中执行代码;您应该使用Task.Run来执行Task

中的代码

答案 1 :(得分:2)

调用另一个async方法中的方法(使用.NET 5.0 async关键字)给我很好。我不确定我是否完全理解您的问题,但请采用以下简单示例。要在起始int和计数之间显示素数,我们可以写

async void DisplayPrimes()
{
    int result = await GetPrimesCountAsync(2, 10000);
    Console.WriteLine(result);
}

其中

Task<int> GetPrimesCountAsync(int start, int count)
{
    return Task.Run(() => 
        ParrallelEnumerable.Range(start, count).COunt(n => 
            Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
}

这里async修饰符告诉编译器在该方法中出现任何歧义时将await视为关键字而不是标识符。这确保了在C#5.0之前编写的可能使用等待作为标识符的代码仍然可以编译而不会出错。 async修饰符只能应用于返回void或Task / Task<TResult>的方法和lambda表达式。

遇到await表达式后,执行(通常)会返回给调用者 - 就像在itterator中使用yeild return一样。但是在返回之前,运行时会向等待的任务附加一个延续,确保当任务完成时,执行会跳回到方法中并继续执行。我想你可以编写上面的方法,显示编译器将其转换为

void DisplayPrimesCount()
{
    var awaiter = GetPrimesCountAsync(2, 100000).GetAwaiter();
    awaiter.OnCompleted(() =>
    {
        int result = awaiter.GetResult();
        Console.WriteLine(result);
    });
}

我希望这会有所帮助。


编辑。所以为了避免任务阻塞(很难说你的情况是什么,因为你没有发布任何代码),你需要将你想要创建的async进程带上“一个级别”

private async Task<bool> TestAsync()
{
    return await Task.Run(() => 
    {
        // Do stuff non-blocking.            
        return true;
    }).ConfigureAwait(continueOnCapturedContext:false);
}

TestAsync这里将能够通过在线程池线程而不是UI上下文上执行其“return”语句来完成。这将立即返回给调用者,但请注意,如果继续使用Task.Result,则任何异常都会包含在AggregateException中,您必须相应处理。

可以找到一个很好的解释on MSDN here。在进入async / await之前,我会建议学习C#4.0任务,因为它可以让您更好地理解并发性。