background thread using Task.Run

1.4k views Asked by At

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.

1

There are 1 answers

8
i3arnon On BEST ANSWER

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.