简体   繁体   中英

What is the best approach/practice for awaiting multiple independent tasks?

var contractSchemaTask = contractSchemaRepository.GetByContractIdAsync(data.Id);
var sectionsTask = sectionRepository.GetAllByContractIdAsync(id);
var latestContractIdTask = contractRepository
    .GetLatestContractIdByFolderIdAsync(data.FolderId.Value);
List<Task> allTasks = new List<Task>()
    { contractSchemaTask, sectionsTask, latestContractIdTask };
while (allTasks.Any())
{
    Task finished = await Task.WhenAny(allTasks);
    if (finished == contractSchemaTask)
    {
        var contractSchema = await contractSchemaTask;
        result.ReturnData.IsSchedules = contractSchema.Count > 0 ? true : false;
    }
    else if (finished == sectionsTask)
    {
        List<Section> sections = await sectionsTask;

        List<TextValueVM> SectionTabList = sections.Count > 0 ? sections
            .OrderBy(a => a.SectionNumber)
            .Select(a => new TextValueVM()
                { Text = a.ToString(), Value = a.Id.ToString() })
            .ToList() : new List<TextValueVM>();

        bool IsSectionsLinked = false;
        int linkSectionCount = sections
            .Where(x => x.LinkSectionId != null && x.LinkSectionId != Guid.Empty)
            .ToList()
            .Count();
        if (linkSectionCount == 0 && sections.Count > 0)
        {
            List<Guid> sectionIds = sections.Select(x => x.Id.Value).ToList();
            List<Section> currentContractLinkSections = await sectionRepository
                .GetSectionsByLinkSectionIdAsync(sectionIds);
            if (currentContractLinkSections.Count > 0)
            {
                IsSectionsLinked = true;
            }
        }
        else if (linkSectionCount > 0)
        {
            IsSectionsLinked = true;
        }
        result.ReturnData.SectionTabList = SectionTabList;
        result.ReturnData.IsSectionsLinked = IsSectionsLinked;
    }
    else if (finished == latestContractIdTask)
    {
        Guid LatestContractId = await latestContractIdTask;
        result.ReturnData.isLatestContract
            = (data.Id == LatestContractId) ? true : false;
    }
    allTasks.Remove(finished);
}

I am working on a asp.net core 3.0 WebAPI project. Above is the sample code for independent tasks that I handle using a while loop. Is there any better or efficient approach for handling independent tasks in the asynchronous programming?

PS: All the 3 tasks are independent and may vary on their response time depending upon the number of records fetched from the database.

You should do it like this:

public Task Main()
{
    var result = new Result();
    return Task.WhenAll(TaskOne(result), TaskTwo(result), TaskThree(result));
}

    private async Task TaskOne(Result result)
    {
        var contractSchema = await contractSchemaRepository.GetByContractIdAsync(data.Id);
        //your logic for task1, set related result properties
    }

    private async Task TaskTwo(Result result)
    {
        var sections = await sectionRepository.GetAllByContractIdAsync(id);
        //your logic for task2, set related result properties
    }

    private async Task TaskThree(Result result)
    {
        var latestContractId = await contractRepository.GetLatestContractIdByFolderIdAsync(data.FolderId.Value);
        //your logic for Task3, set related result properties
    }

Result class should be implemented as thread-safe because tasks can be executed simultaneously. If you just set different properties in each method it should be OK.

Combining Task.WhenAll with Continue allows you to execute code as soon the task finish without having to await the rest of the tasks.

class Test {

    public static async Task Main() {

      var t1 = AsyncWork1().ContinueWith((t) => Console.WriteLine($"Task1 finished with value {t.Result}"));
      var t2 = AsyncWork2().ContinueWith((t) => Console.WriteLine($"Task2 finished with value {t.Result}"));
      var t3 = AsyncWork3().ContinueWith((t) => Console.WriteLine($"Task3 finished with value {t.Result}"));

      await Task.WhenAll(new[] { t1, t2, t3 });

      //here we know that all tasks has been finished and its result behaviour executed.

      Console.ReadKey();    
    }//main

    public static async Task<int> AsyncWork1() {
      await Task.Delay(1000);
      return 1;
    }

    public static async Task<string> AsyncWork2() {
     await Task.Delay(100);
      return "work2";
    }

    public static async Task<bool> AsyncWork3() {
      await Task.Delay(500);
      return true;
    }

  }//class Test

Compare with this:

 class Test {

        public static async Task Main() {

          var t1 = AsyncWork1();
          var t2 = AsyncWork2();
          var t3 = AsyncWork3();

          await Task.WhenAll(new[] { t1, t2, t3 });

         //all task finished but now we have to execute the result behaviour in a sync way          

         Console.WriteLine($"Task1 finished with value {t1.Result}");
         Console.WriteLine($"Task2 finished with value {t2.Result}");
         Console.WriteLine($"Task3 finished with value {t3.Result}");

          Console.ReadKey();    
        }//main

        public static async Task<int> AsyncWork1() {
          await Task.Delay(1000);
          return 1;
        }

        public static async Task<string> AsyncWork2() {
         await Task.Delay(100);
          return "work2";
        }

        public static async Task<bool> AsyncWork3() {
          await Task.Delay(500);
          return true;
        }

      }//class Test

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM