2

I'm trying to implement a nested task inside a loop - this is the pattern I have so far, however I'm far from sure as this is the first time I've used the parallel task library.

The parent (tier) task should wait for the children (node) tasks to complete.

    public int NestedTask(IEnumerable<MatchTier> tierNodes)
    {
        var tier = Task<int>.Factory.StartNew(() =>
        {
            Task<int> node = null;

            foreach(var n in tierNodes)
            {
                node = Task<int>.Factory.StartNew(() =>
                {
                    // Task logic goes here

                    return 1; // temp placeholder
                });

                // if a valid value is returned then exit this loop
            }

            return node.Result;

        });

        return tier.Result;
    }

The child nodes loop until the first valid value is returned, then the loop should be exited, passing the valid value to the parent.

Both the child and parent nodes require a timeout too. Each child will be allowed approx 3 seconds to run after which the process will be timed out and the next node interrogated.

the parent has an overall timeout value of approx 15 - 20 seconds, after which, if no valid response has been recieved, it too should terminate.

Does this seem logical?

dotnetnoob
  • 10,783
  • 20
  • 57
  • 103
  • In all honesty you are only waiting for the last result and returning that. What are you really trying to do? – flindeberg Aug 27 '13 at 08:26
  • Could you please add more details. tierNodes is collecion of your parent node or child node ? How you are getting child nodes from parent nodes. I am not able to see any parent child relationship in th code. A little more info would be helpful – Anand Aug 27 '13 at 08:26
  • @Anand - added more details. – dotnetnoob Aug 27 '13 at 09:21
  • Why do you use a task `tier` if you wait for its result at the end of the method? Or: why don't you just use the inner loop creating `Task`s? – oddparity Aug 27 '13 at 09:32

2 Answers2

2

to wait for a task to complete do

node.Wait();

to wait for task up until some ticks do

node.Wait(timeToWait);

or to wait for them all to complete

Task.WaitAll(tasks);

and you should read here for more information

Pawel Krakowiak
  • 9,940
  • 3
  • 37
  • 55
No Idea For Name
  • 11,411
  • 10
  • 42
  • 70
1

As stated task.Wait(), task.Result (wait and grab result) and Task.WaitAll(theTaskCollection) are the ways to do this. I've changed your implementation slightly to account for that but I'm very unsure of what you really want to return. The outer task I removed since it didn't seem to be needed.

public int NestedTask(IEnumerable<MatchTier> tierNodes)
{
  var tasks = tierNodes.Select(node => Task<int>.Factory.StartNew(() =>
            {
                // Task logic goes here
                return 1; // temp placeholder
            })).ToList(); // Enumerate to start tasks, not doing this would case WaitAll to start them one at a time (i believe)

  if (!Task.WaitAll(tasks, timeOutInMilliseconds))
    // Handle timeout...

  return tasks.First().Result; // Is this what you want?
}

EDIT: Adding modified solution.

public int NestedTask(IEnumerable<string> tierNodes)
{
  int parentTimeout = 15 * 1000;
  int childTimeout = 3 * 1000;

  var tier = Task<int>.Factory.StartNew(() =>
  {
      foreach (var n in tierNodes)
      {
          var node = Task<int>.Factory.StartNew(() =>
          {
              // Task logic goes here
              return 1;
          });

          // If we get the result we return it, else we wait
          if (node.Wait(childTimeout))
              return node.Result;
      }
      throw new Exception("did not get result!");
  });

  if (!tier.Wait(parentTimeout))
  {
      // The child will continue on running though.
      throw new TimeoutException("parent timed out");
  }
  else if (tier.Exception != null)
  {
      // We have an error
      throw tier.Exception.InnerException;
  }

  return tier.Result;
}
flindeberg
  • 4,887
  • 1
  • 24
  • 37
  • The outer task will be needed as the next stage will be to add some timeout logic. However I refrained from doing so for clarity. – dotnetnoob Aug 27 '13 at 09:07
  • @dotnetnoob Why not have the timeout on the lower task level instead? – flindeberg Aug 27 '13 at 09:09
  • Different timeouts will apply to each - a node will have a timeout of 3 seconds and the parernt tier will have a timeout of 15-20 seconds. Each nodes is allowed to run for a specified time before being timed out. The next node is tested and so on until a calid value is returned or all nodes are exhausted. If the timeout on the parent occurs the whole process is abandoned and the next tier will be tested. – dotnetnoob Aug 27 '13 at 09:17
  • @dotnetnoob I added a new solution for your new requirements. Hopefully it helps u! – flindeberg Aug 27 '13 at 11:19
  • Thanks - i'll set up some tests and try it out. – dotnetnoob Aug 27 '13 at 12:01
  • Checked out all scenarios and works great. Thhanks for your help. – dotnetnoob Aug 27 '13 at 13:44