【问题标题】:Declaring method return type Task<int> without async keyword声明没有异步关键字的方法返回类型 Task<int>
【发布时间】:2019-02-16 05:58:45
【问题描述】:

在什么情况下你会在方法签名中不使用async而返回Task&lt;T&gt;

我在下面的代码中有这样的方法,但我无法理解发生了什么。

为什么我下面的示例代码没有执行任何await 语句? IE。为什么Console.WriteLine("4)");Console.WriteLine("3)");return x; 永远不会被执行?

class Program
    {
        static void Main(string[] args)
        {
            TestAsync testAsync = new TestAsync();
            testAsync.Run();

            Console.Read();
        }
    }

    public class TestAsync
    {
        public async void Run()
        {
            Task<int> resultTask = GetInt();
            Console.WriteLine("2)");
            int x = await resultTask;
            Console.WriteLine("4)");
        }
        public async Task<int> GetInt()
        {
            Task<int> GetIntAfterLongWaitTask = GetIntAfterLongWait();
            Console.WriteLine("1)");
            int x = await GetIntAfterLongWaitTask;
            Console.WriteLine("3)");
            return x;
        }

        public Task<int> GetIntAfterLongWait()
        {            
            Task.Run(() =>
            {
                for (int i = 0; i < 500000000; i++)
                {
                    if (i % 10000000 == 0)
                    {
                        Console.WriteLine(i);
                    }
                }
            });

            Console.WriteLine("Returning 23");
            return new Task<int>(() => 23);
        }
    }

/*
Output is:
Returning 23
1)
2)
<list of ints>
*/

【问题讨论】:

  • Task&lt;T&gt; 是可以通过任何方法返回的合法类型。如果它前面没有 async 关键字,那么您根本无法在方法中使用 await 某些东西。
  • 但是为什么编译器不给出警告/编译错误呢?
  • 如果你的方法只需要返回一个任务而不需要等待它本身,你就可以使用它,例如因为它是方法中的最后一条语句。话虽如此,您通常不应该使用new Task。如果要返回包装为任务的值,即完成的任务结果,请使用Task.FromResult(23),它的优点是不会用完像Task.Run 和可能的new Task 这样的线程。

标签: c# async-await task


【解决方案1】:

当您从非async 方法返回Task 时?

Task&lt;T&gt; 被概括为一个 promisefuture 值。无论您是从 async 关键字方法还是从其他来源(如启动的线程或 IO 回调)产生此承诺,调用者都不感兴趣,而只是一种实现策略。这也是为什么接口(或抽象方法定义)根本没有async 关键字的原因(async/await 是一种实现策略)。

您的代码示例

  • 问题 1:您的方法 GetIntAfterLongWait 在两个方面存在缺陷。第一个实例化的Task 被实例化并卸载到线程,但结果从未被拾取(因此从未等待......并且从不延迟任何事情)。
  • 问题 2:第二个任务(您在 GetIntAfterLongWait 中返回的那个)已创建(由具有执行方法的构造函数)但未启动(Task.Start())。其他更简单的方法是静态Task.Run 或(在这种情况下)Task.FromResult。任务(或承诺)永远不会传递结果,因为构造函数中的功能块永远不会被执行。
  • 问题 3Main 方法不等待返回任务的结果(awaitTask.Wait()Task.Result

【讨论】:

    【解决方案2】:

    您的代码中的问题是您实际上是 await 从未启动的任务,因为方法 GetIntAfterLongWait 返回未启动的任务的新实例。所以基本上你有一个死锁,等待根本没有开始的东西。

    您可以返回基本上已经完成的任务Task.FromResult(23),或者您可以实际运行您的任务Task.Run&lt;int&gt;(() =&gt; 23);

    【讨论】:

    【解决方案3】:

    您很可能在GetIntAfterLongWait() 方法中创建了一个新线程。尝试将return new Task&lt;int&gt;(() =&gt; 23); 更改为return Task.FromResult(23);

    有关Task.FromResult 的更多信息,请参阅How to: Create Pre-Computed Tasks 上的 MSDN 文档(带有一个很好的示例)

    【讨论】:

      猜你喜欢
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-04
      • 1970-01-01
      相关资源
      最近更新 更多