0

I am using following code for creating parent and child task. Parent task's job is just wait for 5 sec and child task executes and stored result in shared resource. I have marked that child task is taking time.

Actually I don't know internal mechanism that when child thread is created and start execution parallel ?

Is there any documentation from that I can know or Is there any other best way to implement parent child concept ?

List<Task> taskList = new List<Task>();

Task parentTask = Task.Factory.StartNew(() =>
{
    int index = 0;
    for (int i = 0; i < 10; i++)
    {
        var task = new Task(() => PrintHello(), TaskCreationOptions.AttachedToParent);
        taskList.Add(task);
        index++;
    }
    foreach (Task task in taskList)
    {
        task.Start();
    }
});

//Wait Parent Task.
parentTask.Wait(5000);

EDIT:

Application is too heavy (avg 5 request per sec) and It should give response in 5 sec.

I am using task for better performance. Is there any other way other than task for parallelism ?

i3havi
  • 35
  • 9
  • Tasks are not Threads. You did not necessarily create a new thread here. Threads do not have parents. Tasks _can_ have parents. – Gusdor Aug 07 '15 at 11:43
  • 3
    What is the actual problem you are trying to solve? Why do you want a parent-child relationship between tasks? Why do you create cold tasks? Almost certainly there is a better way to solve the *actual* problem. For example, using `Parallel.Invoke` or using `Task.WhenAll` to wait for the completion of an array of live tasks – Panagiotis Kanavos Aug 07 '15 at 11:48
  • @Gusdor - You are right. I mean child task is taking time. thread and Task are different I have found from http://stackoverflow.com/questions/13429129/task-vs-thread-differences. – i3havi Aug 07 '15 at 11:49
  • check out System.ComponentModel.BackgroundWorker – Adam Finley Aug 07 '15 at 11:50
  • @AdamFinley BackgroundWorker is obsolete and suitable only for WinForms applications anyway. It can't create any sort of relationship between different tasks, execute continuations etc. It's essentially the same thing as calling `Task.Run` and using a `Progress` object to report events, only with the Component overhead and no way to compose multiple actions – Panagiotis Kanavos Aug 07 '15 at 11:51
  • @PanagiotisKanavos - I edited my question. Actually application is too heavy and required high performance. I found that Task is already using thread pool so It will not take creation cost, but task may be long running upto 10 to 15 sec so I haven't used wait for child task. But above code doesn't give guaranty that each child task start as parent task created. Is there any configuration ? – i3havi Aug 07 '15 at 12:27
  • Is this web application ? – Ondrej Svejdar Aug 07 '15 at 12:30
  • @OndrejSvejdar - Yes, It's c# - WCF web application. – i3havi Aug 07 '15 at 12:31
  • @i3i_iavi what is the *actual* problem you are trying to solve? You shouldn't care whether subtasks start immediately or not, it's the scheduler's job to make sure as many of them run concurrently as possible. Having 10K threads blocking one another forever isn't any better than 100 threads processing 10K tasks one after the other. – Panagiotis Kanavos Aug 07 '15 at 12:36
  • Also, depending on WCF's configuration, it probably *already* uses a different thread per request. Multiple tasks would be needed if you called other services in parallel and wanted to avoid blocking while waiting for a response. In which case, you'd need a `await Task.WhenAll(arrayWithTasksCallingOtherServices)`, not a parent with many subtasks. Of course, you could view the task returned by `Task.WhenAll` as that parent task. PS: I have a heavy service too, 10^6 requests/day that require calling 4+ external services – Panagiotis Kanavos Aug 07 '15 at 12:38
  • @PanagiotisKanavos - Yes, I have used 10 to 12 parallel task per request(Thread) as each task is depending other external API's response, Each task response is required but it should not take much time so I have created Parent task and wait child task for configured time. Is there problem of too many task at a time and parallelism cost due to switching tasks ? – i3havi Aug 07 '15 at 12:48

3 Answers3

2

From the comments, it appears that each WCF request needs responses from 10+ external services. In this case, it's best to call each service asynchronously and await for all of the resulting tasks to complete with await Task.WhenAll(tasks);, eg:

public async Task CallManyMethods(string someData)
{ 
    var tasks=new []{
        CallSvc1Async(someData),
        CallSvc2Async(someData),
    }
    var results=await Task.WhenAll(tasks);
    ...
    //Unpack the results and keep processing them
}

public async Task<string> CallSvc1Async(string someData)
{
    var response=await _svc1Proxy.GetStuffAsync(someData);
    //build a result from the response
    return result;
}

public async Task<string> CallSvc2Async(string someData)
{
    var url=....
    var json=await _httpClient.GetStringAsync(url);
    ....
    return result;
}

All methods return strings for demonstration purposes only.

Each method will send the call to the external service and then release its thread until a response is received. This way, threads aren't blocked waiting for responses and the total wait time is determined only by the slowest external service.

CallManyMethods doesn't block either. The executing thread will be released when await Task.WhenAll gets executed. Once all calls complete, execution will resume after the await line.

The result is that there is no need to create parent and child tasks, as the TPL can handle this scenario already. Overhead is minimal because no thread blocks waiting for the external services to complete.

This means that a small number of threads can handle a far larger number of requests.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Definitely async IO is a way to go if he's performing IO-extensive and not CPU-intensive operations. – Ondrej Svejdar Aug 07 '15 at 13:38
  • @Panagiotis Kanavos - Thanks for your answer! you are right I can use method but I think, Task.WhenAll(tasks) executes when all async method are executed. If async method take more than 5 sec time then I don't want to wait for that asyn method and want to continue with main thread. – i3havi Aug 07 '15 at 14:03
0

I'll quote @PanagiotisKanavos - there is no reason to have startup task that will fire off rest of them. You're probably running into a problem with thread pool starvation - you can create only so many threads at once - after that you'll have to wait for creating new thread; also you're not checking if the task will finish or not (which is not great from reliability point of view)

parentTask.Wait(5000);

Will just wait 5sec and continue - the parentTask won't be killed - it returns a boolean telling you if the task did or did not finished in time, but if the task fired of new thread the thread will still run.

Way how to force low latency & reliability on webservice performing some lengthy operation:

  1. Persist the incoming request into persistent storage (db, cloud, etc.)
  2. Create batch application (window service) that will get the records from the queue and will execute them

If your client need a result of this lengthy operation you have only one option - scale up (web farm / cloud).

Also note that more threads doesn't equal better performance - threads are great for waiting on IO operation or if you have multiple cores on the box in question, but if there is no IO operation and only one core, you're actually making your code slower.

Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • Application server has 8 core and 16 GB RAM. Yes, all 10 to 12 task haven't IO operation but I want all should be run parallel, fast and return each task result in 4 to 5 sec. Is there any other way of parallelism ? – i3havi Aug 07 '15 at 13:02
0

I would suggest you to refer below component that may solve your problem.

Octopus.TaskTree

There's flexibility that you can await on parent task, start children execution in series or concurrent fashion.

Please refer the code snippet given that may give you the clear understanding of the component's purpose.

Gokul E
  • 1,356
  • 2
  • 13
  • 28