【问题标题】:Do I need to return anything from an async task? [duplicate]我需要从异步任务中返回任何东西吗? [复制]
【发布时间】:2020-02-22 00:15:40
【问题描述】:

我有以下代码:

    public static async void PopulateMetrics()
    {
        await Task.Run(() =>
        {
            if (App.CPUSpeed == 0)
            {
                var stopWatch = Stopwatch.StartNew();
                stopWatch.Start();
                ArrayList al = new ArrayList(); for (int i = 0; i < 5000000; i++) al.Add("hello");
                App.CPUSpeed = 20000 / stopWatch.ElapsedMilliseconds;
            }
        });

    }

IDE 告诉我异步方法不应返回 void。让它返回 Task&lt;bool&gt; 并返回 true 可以解决这个问题,但需要吗?

在以下之间调用它也会有什么区别:

_ = PopulateMetrics()

await PopulateMetrics()

这就是我所拥有的调用方法。请注意,除了 PopulateMetrics 之外,我在每个异步方法中都有异常处理。

        if (Connectivity.NetworkAccess == NetworkAccess.Internet)
        {
            if (Settings.Rev == REV.No && (new[] { 15, 30, 50 }).Contains(Settings.Trk2))
            {
                _ = ReviewAppAsync(Settings.Trk2);
            }
            if (App.devIsPhysical && (new[] { 10, 20, 30 }).Contains(Settings.Trk2))
            {
                _ = CheckLatestVersion();
            }
            _ = Helper.PopulateMetrics();
            _ = Helper.LogStart();
        }

【问题讨论】:

  • async void 只能在事件处理程序中使用。否则这种做法很容易引发死锁!因为你正在混合同步和异步处理

标签: c#


【解决方案1】:

通常,当非异步方法返回 void 时,其异步对应方应返回 Task

public static async Task PopulateMetrics()

According to Microsoft,您应该仅在实现事件处理程序时使用 void 从异步方法返回:

返回无效的异步方法有一个特定目的:使异步事件处理程序成为可能。有可能有一个返回一些实际类型的事件处理程序,但这不适用于该语言;调用返回类型的事件处理程序非常尴尬,并且事件处理程序实际上返回某些东西的概念没有多大意义。事件处理程序自然返回 void,因此异步方法返回 void,以便您可以拥有异步事件处理程序。

【讨论】:

  • 我把它改成了Task,编译器没有给出警告。那是因为 await Task.Run 返回一个任务吗?它的调用方式如何。 _= 或等待。有什么区别吗?
  • @Alan2 当您在没有await 的情况下执行_ = FooAsync() 时,呼叫将变为“一劳永逸”。通常,您希望在某个时候直接调用await,或者通过在Task.WhenAny/Task.WhenAll 上调用await,并将异步调用中的Task 作为参数传递。
【解决方案2】:

1) 通常,您会想要返回一个任务。主要的例外应该是当您需要具有 void 返回类型(用于事件)时。如果没有理由不允许调用者等待您的任务,为什么不允许呢?

2) 返回 void 的异步方法在另一方面是特殊的:它们代表顶级异步操作,并且当您的任务返回异常时,它们会发挥作用。最简单的方法是通过示例来显示差异:

    static async void f()
    {
        await h();
    }

    static async Task g()
    {
        await h();
    }

    static async Task h()
    {
        throw new NotImplementedException();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        f();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        g();
    }

    private void button3_Click(object sender, EventArgs e)
    {
        GC.Collect();
    }

f 的异常总是被“观察到”的。离开顶级异步方法的异常被简单地视为任何其他未处理的异常。从未观察到 g 的异常。当垃圾收集器来清理任务时,它看到任务导致异常,没有人处理异常。发生这种情况时,TaskScheduler.UnobservedTaskException 处理程序运行。你不应该让这种情况发生。要使用您的示例,

    public static async void AsyncMethod2(int num)
    {
        await Task.Factory.StartNew(() => Thread.Sleep(num));
    }

是的,在这里使用 async 和 await,它们可以确保您的方法在抛出异常时仍然正常工作。

欲了解更多信息,请参阅:http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

【讨论】:

  • 如果我在每个方法中都有异常处理,调用方法是 _ = xx 与 await xx 相同吗?
【解决方案3】:

只需将返回类型设置为 Task 即可摆脱 IDE 警告:

 public static async Task PopulateMetrics()
    {
        await Task.Run(() =>
        {
            if (App.CPUSpeed == 0)
            {
                var stopWatch = Stopwatch.StartNew();
                stopWatch.Start();
                ArrayList al = new ArrayList(); for (int i = 0; i < 5000000; i++) al.Add("hello");
                App.CPUSpeed = 20000 / stopWatch.ElapsedMilliseconds;
            }
        });
    }

关于两次调用的区别,你一定认为调用异步方法就像启动一个新线程:当前线程在等待任务或被要求其结果之前不会被阻塞。 考虑这段代码:

class Program
{
   static async Task Main() // Compiler will warn you 'cause you're not awaiting!
   {
        _ = PopulateMetrics();

       // do something else
   }
}

程序可能会在PopulateMetrics 任务完成之前退出。 由于 PopulateMetrics 返回异步任务,您应该这样做:

class Program
{
   static async Task Main() 
   {
       var popMetricsTask = PopulateMetrics();

       // do something else

       popMetricsTask.Wait(); // or: await popMetricsTask;
   }
}

在退出程序之前确保您的任务已经完成。

【讨论】:

    猜你喜欢
    • 2020-08-12
    • 2017-05-28
    • 2017-01-04
    • 2017-05-26
    • 1970-01-01
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多