Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

background thread using Task.Run

Do you see any pitfalls or issues when spawning off two separate tasks for an Oracle db query and Active Directory query and then waiting for both.

Below is a very basic stripped down example. Essentially we have an employee object that gets created from pieces of info from AD and from an Oracle DB. (called sequentially)

var partialEmployeeA=ActiveDirectoryLookup(employeeID);

var partialEmployeeB=OracleDBLookup(employeeID);

var finalEmployee=Merge(partialEmployeeA,partialEmployeeB);

At this point Employee object has been created and pieced together from both queries and can be used. This has worked without issue, but if each of these calls were its own task would you see any issues from a scaling view point? (excluding any other obvious code issues)

Employee partialEmployeeA;
Employee partialEmployeeB;

var t1 = Task.Run(() => {
   partialEmployeeA=ActiveDirectoryLookup(employeeID);
});

var t2 = Task.Run(() => {
   partialEmployeeB=OracleDBLookup(employeeID);
});,

Task.WaitAll(t1, t2);
var finalEmployee=Merge(partialEmployeeA,partialEmployeeB);

I did some test with the stopwatch class and the Task version comes back faster every time (avg: 100-120ms vs 200-250ms) and has no problem, but wasn't sure how this scaled on a multicore system. I've not done a lot with TPL, but was curious on this approach.

like image 605
jdross Avatar asked Jun 08 '15 23:06

jdross


People also ask

Does task run Use thread pool?

One way to turn a synchronous operation into an asynchronous one is to run it on a separate thread, and that's where Task. Run comes in. The Run method queues code to run on a different thread (usually from the "thread pool", which is a set of worker threads managed for your application by . NET).

What's the best way to execute code in the background in a separate thread?

You can use a Handler to enqueue an action to be performed on a different thread. To specify the thread on which to run the action, construct the Handler using a Looper for the thread. A Looper is an object that runs the message loop for an associated thread.


1 Answers

I don't see any problems with this, these are different services with different requests that probably don't share any state.

However, you should realize that in both cases you are taking up 3 threads that are blocked throughout the entire asynchronous (I/O) operation.

It would be faster to perform these operations in parallel by utilizing multiple threads. But it won't actually be more scalable.

To do this "right" without blocking a thread and using up resources you need to treat these operations as truly async and not just on a background thread:

var partialEmployeeATask = ActiveDirectoryLookupAsync(employeeID);
var partialEmployeeBTask = OracleDBLookupAsync(employeeID);

await Task.WhenAll(partialEmployeeATask, partialEmployeeBTask)
var finalEmployee = Merge(await partialEmployeeATask, await partialEmployeeBTask);

That requires changing the API to support asynchronous requests in some form. If the API is not under your control that can be an issue. If that can't be done at least use Task.Run only once and use the "main" thread to the other part.

like image 89
i3arnon Avatar answered Sep 19 '22 06:09

i3arnon