0

I am new in Task Based programming. I have to call a WCF service Asynchronously and start a Task to wait for it as I do not want to wait in the Same Method so I have written code something like this

void MyMainMethod()
{
   for(int j=0;j<10; j++)
   {

      int I = 100;
      Task<response> res =  _client.GetValueAsnc(request);

       //Do some work

       Task.Run(()=> WaitForResponse(res , I));
    }
}

Async Task WaitForResponse(Task<response> res , int I)
{
   await res;

   if(res.responsecode == "Success")
   {
      //udatateDB...
   }
 
   else
   {
      //update DB with Error Message..
   }
}

That way, If I call this service 10 times in a loop, it will start 10 tasks and give me response and instead of waiting for response in MyMainMethod() I am starting a separate task for each request.

Please let me know if this is correct approach or I am doing some major mistake here and also in case more details are required from my side to explain the question.

Thanks in Advance.

Stefan
  • 17,448
  • 11
  • 60
  • 79
renu
  • 3
  • 2
  • How about [Duplex Services](https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/duplex-services) instead? – Marshal Mar 23 '21 at 19:49

2 Answers2

0

What you try to achieve is a good thing. Not blocking some main thread is a good idea and the way you do it is going to work.

However, if you do it this way, you have to manually control the number of tasks. You probably do not want the number to go too high, otherwise too much of parallelism might hurt performance.

There are classes in .net that help to manage a queue of tasks by what is called a thread pool. You configure the threadpool with a known maximum number of threads, and then just queue tasks to the pool. The threadpool class takes care of emptying the queue and assigning tasks to free threads in a pool.

You can learn more about thread pools here on ms docs

The sample below is from the MS docs site.

using System;
using System.Threading;

public class Example 
{
    public static void Main() 
    {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(ThreadProc);
        Console.WriteLine("Main thread does some work, then sleeps.");
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo) 
    {
        // No state object was passed to QueueUserWorkItem, so stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}
// The example displays output like the following:
//       Main thread does some work, then sleeps.
//       Hello from the thread pool.
//       Main thread exits.
Mirronelli
  • 740
  • 5
  • 14
  • Ok thanks Alot..so when we say "However, if you do it this way, you have to manually control the number of tasks. You probably do not want the number to go too high, otherwise too much of parallelism might hurt performance" so how do we control number of tasks in such cases and when we say number too high.. what number can be too high.. asking as I am clueless on this Task based asyn programming – renu Mar 23 '21 at 20:08
  • The number that is too high depends on what the tasks do, how many cores you have available etc. For example if the task do a blocking CPU intensive work, going higher than the number of cores (possibly times 2 if you have hyperthreading) will not help the performance. There is no simple rule to the numer of tasks and it may be better to do some masurements in the specific scenario you implement. In some situations if you have a lot of tasks that do a lot of async work, they can reuse the physical threads. All this is managed by the thread pool and is quite complex. – Mirronelli Mar 23 '21 at 20:14
  • Thanks Mirronelli, I will try this... Thanks a lot – renu Mar 24 '21 at 09:07
0

Why dont you use Task Parallel Library instead on Thread Pool.

class Client
{
    internal async Task<string> GetValueAsnc()
    {
        Console.WriteLine("GetValueAsync");
        await Task.Delay(TimeSpan.FromSeconds(2));
        return "success";
    }
}
class Program
{
    private static readonly Client _client = new Client();

    static void Main(string[] args)
    {
        var tasks = new List<Task>();
        for (int j = 0; j < 10; j++)
        {
            tasks.Add(WaitForResponse());
        }

        Task.WhenAll(tasks);
        Console.WriteLine("Tasks finished");
        Console.ReadLine();
    }

    static async Task WaitForResponse()
    {
        var res = await _client.GetValueAsnc();

        if (res == "Success")
        {
            //udatateDB...
        }

        else
        {
            //update DB with Error Message..
        }
    }
}

It has a better api than ThreadPool, and no need to worry about thread starvation this way

CaveCoder
  • 791
  • 3
  • 17
  • Thanks Cavecode, can you please explain me difference between your suggestion and my code that way I will be able to understand it more.... thanks alot – renu Mar 23 '21 at 20:49
  • You need to await the call to `Task.WhenAll`... or you need to use `Task.WaitAll`. – John Wu Mar 23 '21 at 21:47
  • @renu please check here https://stackoverflow.com/questions/1774670/c-sharp-threadpool-vs-tasks Tasks are just wrappers for ThreadPool, for most use cases its better because you dont have to worry about details like controlling the number of active threads – CaveCoder Mar 23 '21 at 23:57
  • @CaveCoder Can you please tell me what do we call the approach that I followed in my code. Is it Threadpool... But I am using tasks so little confused – renu Mar 24 '21 at 09:23
  • @renu On your code you are using tasks, just not on the most correct way, other answer code is ThreadPool – CaveCoder Mar 24 '21 at 12:08