如何通过await获取异步方法的确切结果而无需使用Task.Result?

4

我想尝试使用async和await进行实验,但是结果很糟糕。 我有一个需要异步运行两个方法的方法(它部分工作)。

public void Run()
{
            Task[] tasks = new Task[2];
            tasks[0] = Task.Factory.StartNew(DisplayInt);
            tasks[1] = Task.Factory.StartNew(DisplayString);

            //block thread until tasks end
            Task.WaitAll(tasks);
}

有两种常用的方法

public async void DisplayInt()
    {
        Task<int> task = new Task<int>(
            () => 10);
        task.Start();
        Console.WriteLine(await task);
    }

    public async void DisplayString()
    {
        Task<string> task = new Task<string>(
           () => "ok" );
        task.Start();
        Console.WriteLine(await task);
   }

通常我得到以下结果:

1)10 ok

或者

2)ok 10

但有时候,我会得到:

3)什么都没有

如何在不使用task.Result的情况下,通过await从异步方法中获取确切的结果?


1
从许多线程向控制台写入内容是否安全?我现在记不清了。 - usr
1
是的,链接:https://msdn.microsoft.com/zh-cn/library/system.console.aspx 和 https://dev59.com/rnNA5IYBdhLWcg3wIqLr。 - Bushuev
你也可以使用task.GetAwaiter().GetResult(),它与task.Result不同之处在于它不会用AggregateException包装异常。 - noseratio - open to work
2个回答

6
我建议你阅读一些介绍性文章,例如我自己的async入门,然后再看我的MSDN关于异步最佳实践的文章。如果你只是简单地编写代码,那么你会遇到很多问题。
特别是,你不应该使用Task.Factory.StartNewTask构造函数或者Task.Start;而且你应该避免使用async void(所有链接都是指向我在博客中详细解释的内容)。
回答你实际的问题:

如何使用await从async方法获取确切的结果,而不使用task.Result或它不可行?

要获取任务的结果,你可以通过await异步等待任务完成,也可以同步(阻塞)等待任务完成(使用Result)。如果你问的是是否有“其他方式”,那么答案是否定的。

1
欢迎来到 SO...
嗯,在你的情况下,初始化这两个任务需要更多的时间,然后再运行方法。这就是为什么有时候第二个任务会在第一个任务之前完成(如果第二个任务的初始化时间更短)。如果你将你的 DisplayString 方法更改为:
    public static async void DisplayString()
    {
        Task<string> task = new Task<string>(
            () => { Thread.Sleep(10); return "ok"; });
        task.Start();
        Console.WriteLine(await task);
    }

现在DisplayString方法执行需要大约10毫秒,它将始终产生以下结果:

10    
ok

P.S. 正如 Stephen Cleary 指出的那样,你可以阅读一些关于 async / await 的基础文章。我也建议在 WinForms 项目上进行测试,而不是使用 Console


基于睡眠的同步并不是一个很好的实践方式 - 我认为你应该加上它仅适用于演示目的。一些缺乏经验的人可能会将你的例子作为使用模式。 - DarkWanderer

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