2
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?

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

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Kunal Patil
  • 261
  • 1
  • 2
  • 5
  • 3
    `Task.WhenAll` is a good option: https://stackoverflow.com/questions/12337671/using-async-await-for-multiple-tasks – timur Dec 03 '19 at 09:57
  • Take a look at this: [Awaiting multiple Tasks with different results](https://stackoverflow.com/questions/17197699/awaiting-multiple-tasks-with-different-results) – Theodor Zoulias Dec 03 '19 at 10:28

2 Answers2

3

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.

mtkachenko
  • 5,389
  • 9
  • 38
  • 68
2

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
jlvaquero
  • 8,571
  • 1
  • 29
  • 45