在async / await C#中苦苦挣扎

时间:2016-02-16 13:00:53

标签: c# .net asynchronous async-await

我读过很多关于async/await的内容,但我仍然不了解以下情况。

我的问题是,我应该实现我的"包装" DoSomething()中的方法或DoSomethingAsync()中的方法。

那么更好(以及为什么):我在包装器方法中使用await还是直接返回任务?

        public static async void Main()
        {
            await DoSomething();
            await DoSomethingAsync();
        }

        private static Task DoSomething()
        {
            return MyLibrary.DoSomethingAsync();
        }

        private static async Task DoSomethingAsync()
        {
            await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
        }

        public class MyLibrary
        {
            public static async Task DoSomethingAsync()
            {
                // Here is some I/O
            }
        }

3 个答案:

答案 0 :(得分:8)

Async / Await仍然相对较新,但有一些很好的做法可以帮助澄清API。基础是:

  • 将自己声明为async的方法意味着以后期待await
  • async为您隐式创建Task
  • await就像一个书签。应用程序将继续使用await关键字。
  • 你不能await任何不是IAwaitable的东西(最常见的是Task)(citation

在同时存在异步调用和同步调用的应用程序中,我们采用了命名约定:

  • async调用返回TaskTask<T>,并将Async附加到名称的末尾。
  • 同步调用(默认)只是像任何方法一样工作,没有特殊约定。

通常,有两种方法可以做同样的事情,但一种是同步的,另一种不是。你可以用两种不同的方式实现它,也可以用另一种方式包装一种方式。这实际上取决于您的需求以及为您提供响应更快的应用程序。

在上面的示例中,处理异步和普通方法调用的正确方法是MyLibrary公开两种方法。这个例子是这样的:

 public static class MyLibrary
 {
     public static void DoSomething()
     {
         // do some work
     }

     public static async Task DoSomethingAsync()
     {
         // do similar work but use async API,
         // can also simply call DoSomething().
     }
 }

 // In another part of code would be called like this:
 public static async Task BiggerMethod()
 {
     MyLibrary.DoSomething();
     await MyLibrary.DoSomethingAsync();
 }

您要避免的是使用常规方法包装async方法。只要您直接使用Task,就会失去asyncawait的所有好处,并且会引入代码可能陷入僵局的位置。

答案 1 :(得分:4)

Berin的答案很好,但未明确解决您问题中的特定情况,即以下示例:

1:直接返回任务

private static Task DoSomething()
{
    return MyLibrary.DoSomethingAsync();
}

2:等待任务并返回结果

private static async Task DoSomethingAsync()
{
    await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
}

在这种情况下,直接返回Task和等待Task并返回响应之间的唯一区别是 - 在后一种情况下 - 必须由框架创建状态机来管理等待Task的方法的开始,暂停和继续。这会产生一些性能开销。

一般来说,如果你可以返回一个Task并允许它等待更高,你应该。然而,在大多数(但肯定不是全部)真实案例中,这将是不可能的,因为您将希望在返回之前执行某些结果处理(这正是async / await帮助您实现的目标)。 / p>

答案 2 :(得分:0)

单线的情况没有区别。 但是在at least two-async-liners的情况下,例如:

public static async void Main()
{
    await DoSomething();
    await DoSomethingAsync();
}

private static Task DoSomethingTwice()
{
    var do1 = MyLibrary.DoSomethingAsync();

    // when you await DoSomethingTwice, next line's reached
    // when do1 task may not be completed
    var do2 = MyLibrary.DoSomethingAsync();

    // return what???
    // how to combine them?

    // okay, you can do that
    return Task.WhenAll(do1, do2)
}

private static async Task DoSomethingTwiceAsync()
{
    await MyLibrary.DoSomethingAsync().ConfigureAwait(false);

    // when you await DoSomethingTwiceAsync, next line's reached 
    // when prev-line task is completed
    await MyLibrary.DoSomethingAsync().ConfigureAwait(false);
}

public class MyLibrary
{
    public static async Task DoSomethingAsync()
    {
        // Here is some I/O
    }
}

要点:

  • 如果你必须将方法组织成一系列连续的异常工作和平:doAsync1() - &gt; doAsync2() - &gt; doAsync3()

即。每一个下一个和平都需要完成前一个和平的结果,那么你应该等待每个电话:

async Task DoAsync()
{
    await doAsync1();
    await doAsync2();
    await doAsync3();
}
  • 但您无法在non-async方法中使用等待。因此,您无法以Task DoSomething()样式执行,只能async Task DoSomethingAsync()
  • 如果没有异步链 - 你可以做任何你想做的事情,如上面的第一个例子那样