C#异步编程中不使用await关键字

4
在这里的文档中:http://msdn.microsoft.com/en-us/library/hh191443.aspx,它指出:

如果异步方法没有使用await运算符来标记暂停点,该方法将像同步方法一样执行,尽管有异步修饰符。编译器会为这些方法发出警告。

我认为这是警告内容:

此异步方法缺少'await'运算符并将以同步方式运行。请考虑使用'await'运算符等待非阻塞API调用,或使用'await Task.Run(...)'在后台线程上进行CPU绑定工作。

然后,在另一个引用链接中,http://msdn.microsoft.com/en-us/library/windows/apps/hh994635.aspx,它展示的示例如下:
public class Example
{
    // ...
    private async void NextMove_Click(object sender, RoutedEventArgs e)
    {
        await Task.Run(() => ComputeNextMove());
        // Update the UI with results
    }

    private async Task ComputeNextMove()
    {
        // ...
    }
    // ...
}

这里,我假设ComputeNextMove方法基本上是同步的,它本身没有调用await。那么这似乎与编译器警告相矛盾(除非这是一个错误的示例...)。
如果我在我的异步调用堆栈的结尾没有调用.net异步方法,比如HttpClient.GetStringAsync,并且我确实想要实现一些具体的“长时间运行”的同步逻辑,是否有更合适的方法呢?
也许我的假设是不正确的,ComputeNextMove可以声明为private void ComputeNextMove(),这将不会产生警告。

1
这很令人困惑。你正在调用 Task.Run(Func<Task>),它会等待返回的任务。 - SLaks
Task 本身调用 await - Jon
如果代码中有异步但没有等待,它就是同步的 - 当代码同时包含这两个时:“我认为它是同步的。”我不知道该怎么办。 - Magus
1个回答

13

是的,这只是一个不好的例子。

如果ComputeNextMove确实只是一个同步方法,没有真正异步执行任何操作(如描述所示),它就不应该被声明为async,而应该声明为private void ComputeNextMove()

由于使用了Task.RunComputeNextMove仍将在后台线程上执行。

我很可能会在这里使用方法组转换,而不是lambda表达式:

await Task.Run((Action) ComputeNextMove);

谢谢Jon,这可能是一个非常愚蠢的问题,但我看到的大多数示例都展示了编写一个异步方法,该方法本质上调用了一个.net异步方法,而我对于我自己想要编写这样的方法有点模糊。根据回复(以及将HttpClient.GetStringAsync反编译为示例),似乎最终涉及到某个被等待的任务。 - Novox
@Novox:虽然通常情况下它是一个任务,但并不总是如此。是的,写自己的“原始”的异步方法的人相对较少。通常你最终会经由许多其他异步方法,进入框架*Async方法...或者为特定的同步工作创建一个任务,这些工作你只是不想在当前线程上执行。 - Jon Skeet
在你的回答中,你使用了方法组转换而不是lambda表达式。为什么这样做?这样做有性能优势吗? - Bilal Fazlani
2
@BilalFazlani:不,它只是简单了一点。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接