【问题标题】:Basic Understanding of Async Await Programming in C#C#中Async Await编程的基本理解
【发布时间】:2019-08-13 10:16:02
【问题描述】:

我试图理解Async/Await 编程模型。我写了一个示例程序来理解这一点。

我编写了 3 个独立的异步方法,分别命名为 GetFirstValueGetSecondValueGetThirdValue。 有一个名为M1的方法,它异步执行上述3个方法,并返回上述3个方法的拼接结果。

我的主要想法是,如果方法 GetFirstValue 需要 5 秒,GetSecondValue 需要 7 秒,GetThirdValue 需要 8 秒。然后,M1 应该会在 20 秒内返回。由于这 3 种方法不同步。

但是因为我没有正确理解这个概念。我做错了什么。这是我正在研究的完整程序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LearningAsyncProgramming
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();

            AsyncMethodsClass asyncMethods = new AsyncMethodsClass();
            Console.WriteLine(asyncMethods.M1().Result);
            watch.Stop();

            Console.WriteLine(watch.ElapsedMilliseconds/1000);
        }
    }

    class AsyncMethodsClass
    {
        public async Task<string> M1()
        {
            string retVal = string.Empty;

            int v1 = await GetFirstValue();
            int v2 = await GetSecondValue();
            int v3 = await GetThirdValue();

            return string.Concat( v1,"-",v2,"-",v3);
        }

        private async Task<int> GetFirstValue()
        {
            int a = await GetTimer();
            return a;
        }
        private async Task<int> GetSecondValue()
        {
            int a = await GetTimer();
            return a;
        }
        private async Task<int> GetThirdValue()
        {
            int a = await GetTimer();
            return a;
        }

        private async Task<int> GetTimer()
        {
            int someNumber = new Random().Next(5,9);

            Thread.Sleep(someNumber * 1000);
            return someNumber;
        }
    }
}

这是实施答案中的建议后的更新代码。它完全符合我的预期。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LearningAsyncProgramming
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();

            AsyncMethodsClass asyncMethods = new AsyncMethodsClass();
            Console.WriteLine(asyncMethods.M1().Result);
            watch.Stop();

            Console.WriteLine(watch.ElapsedMilliseconds/1000);
        }
    }

    class AsyncMethodsClass
    {
        public async Task<string> M1()
        {
            // Start all the functions, but don't wait just yet
            var t1 = GetFirstValue();
            var t2 = GetSecondValue();
            var t3 = GetThirdValue();

            return string.Concat( await t1,"-",await t2,"-",await t3);
        }

        private async Task<int> GetFirstValue()
        {
            int a = await GetTimer();
            return a;
        }
        private async Task<int> GetSecondValue()
        {
            int a = await GetTimer();
            return a;
        }
        private async Task<int> GetThirdValue()
        {
            int a = await GetTimer();
            return a;
        }

        private async Task<int> GetTimer()
        {
            int someNumber = new Random().Next(5,9);

            await Task.Delay(someNumber * 1000);
            return someNumber;
        }
    }
}

【问题讨论】:

  • 在任务中使用Thread.Sleep不是一个好主意,请改用await Task.Delay(...)
  • “我做错了什么”,你能详细说明你为什么这么说吗?这里有什么不符合您的期望?除了我上面提到的 Thread.Sleep 之外,我个人肯定会在这里做一些不同的事情,但这不会使它们出错,但是知道你打算代码做什么,和/或你期望它做什么,它没有/没有,将帮助我们为您的问题制定最佳/正确答案。
  • 如果“有什么问题”是您期望三个调用并行运行,本质上 M1 的执行时间应该与三个调用中最长的一样长,那么答案是您调用了每个调用,在你打电话给下一个之前等待他们回来。而是检查@Lukas 提供的答案,它可能正是您想要的。
  • 这个video 真的帮助我理解了等待的正确用法以及在制作/使用异步方法时会发生什么。
  • @LasseVågsætherKarlsen 是的,你的第三条评论就是我想要的。我想并行运行所有 3 个方法,并在所有方法完成执行后返回结果。

标签: c# .net multithreading async-await


【解决方案1】:

问题是您正在以伪异步方式运行Get 方法。在调用GetSecondValueGetThirdValue 之前调用GetFirstValue 并等待函数完成。

您要做的是并行运行它们,然后等待它们全部完成:

// Start all the functions, but don't wait just yet
var t1 = GetFirstValue();
var t2 = GetSecondValue();
var t3 = GetThirdValue();

// Wait for them all to complete in parallel
await Task.WhenAll(t1, t2, t3);

// Get the results from the task
int v1 = t1.Result;
int v2 = t2.Result;
int v3 = t3.Result;

或者,您可以删除 WhenAll 并等待各个任务。因为它们现在都在运行,所以基本相同:

// Start all the functions, but don't wait just yet
var t1 = GetFirstValue();
var t2 = GetSecondValue();
var t3 = GetThirdValue();

// All the tasks are running, so get the results from the task
int v1 = await t1;
int v2 = await t2;
int v3 = await t3;

【讨论】:

  • 我们有替代await Task.WhenAll(t1, t2, t3); 喜欢int v1 = await t1; int v2 = await t2; int v3 = await t3;
  • @SandeepKushwah - 是的,你可以这样做。我会更新答案以表明这一点
【解决方案2】:
int v1 = await GetFirstValue();
int v2 = await GetSecondValue();
int v3 = await GetThirdValue();

在这种情况下使用await 在每次调用之前阻止代码继续;您希望保留从这些调用返回的所有任务的集合(没有await),然后对它们调用Task.WaitAll

此代码的修订版本:

var firstTask = GetFirstValue();
var secondTask = GetSecondValue();
var thirdTask = GetThirdValue();

int v1 = await firstTask;
int v2 = await secondTask;
int v3 = await thirdTask;

【讨论】:

  • 你应该编辑他应该如何重写代码。
猜你喜欢
  • 1970-01-01
  • 2018-04-12
  • 1970-01-01
  • 2012-12-20
  • 1970-01-01
  • 2017-11-14
  • 2020-03-25
  • 2018-10-13
  • 1970-01-01
相关资源
最近更新 更多