Search code examples
c#multiprocessingwindows-services

Task.run() for multitasks runs


I want to run more than one tasks simultaneous based on a return value. Below is the rough code for what I want.

    class Program
    {
        static void tempFunc(string username,string password, ref Queue<KeyValuePair<string, string>> queue)
        {
            for(int i=0;i<10;i++)
            {
                Task.Delay(100000);
                Console.WriteLine(username + i);
            }
            queue.Enqueue(new KeyValuePair<string, string>(username, password));
        }
        static void Main(string[] args)
        {
            // A queue which is storing the username and password for different sessions and they need
            // to be passed to the method being called in Tasks.run
            Queue<KeyValuePair<string, string>> queue = new Queue<KeyValuePair<string, string>>();
            queue.Enqueue(new KeyValuePair<string, string>("user1", "password1"));
            queue.Enqueue(new KeyValuePair<string, string>("user2", "password2"));
            queue.Enqueue(new KeyValuePair<string, string>("user3", "password3"));

            while(true)
            {  // Based on the condition mentioned here(this condition is a method in real which returns a list of
               //string, which I will be passing as a parameter to the method being called in Tasks.run but I haven't put that in code here)
               if(condition)
               { 
                   if(queue.Count != 0)
                   {
                       KeyValuePair<string, string> temp = queue.Dequeue();
                       string username = temp.Key;
                       string password = temp.Value;

                       Task.Run(() => tempFunc(username, password, ref queue));
                   }
               }
            }
        }
    }

Idea is to have a pool of usernameand password, when a task is done, it will enqueue the used username and password so that it can be used again. There can be multiple tasks and they are not dependent on each other i.e. when one task is running other task can use other set of username and password and call method. and this all is running as a part of windows service. Issue is when I am using the mentioned code, It seems to be working synchronously. i.e. waiting for one task to be finished and then run other task after that. What am I doing wrong? or I am using Tasks.run wrong way.


Solution

  • You are almost there. Few changes and your program will start working asynchronously.

    The changes I'll recommend are:

    A) Change the function tempFund to include aysnc. And no need to include queue as parameter to this function. You can add user back to queue in calling function once task is complete.

    public static async Task tempFunc(string username, string password)
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Before work start : {0}", username + i);
            await Task.Delay(2000);  //I have reduced it. OP can use his time
            Console.WriteLine("After work complete : {0}", username + i);
        }
    }
    

    B) Use ConcurrentQueue for thread-safe operations. The same has been suggested by Jones.

    //Use ConcurrentQueue
    
    var queue = new ConcurrentQueue<KeyValuePair<string, string>>();
    

    C) Modify the if block as:

      if (queue.Count != 0)
      {
          var temp = new KeyValuePair<string, string>();
          queue.TryDequeue(out temp);
          string username = temp.Key;
          string password = temp.Value;
    
          Task.Run(async () =>
          {
              Console.WriteLine("before Task start : {0}", username);
              await tempFunc(username, password);
              Console.WriteLine("after Task Ends : {0}", username);
              queue.Enqueue(new KeyValuePair<string, string>(username, password));
          });
    

    Make a note of additional logs which will make it obvious that program in running asynchronously.