0

I have scenario where I have to call a same database stored procedure for each item in a list. I don't want to use foreach as it will degrade the performance, Which will be best option parllel foeach or async/await foreach?

Below is sample code

public Task<List<object>> CallMethod()
{
    foreach(var obj in input)
    {
        List.Add(await Task.Run(() =>CallDatabase(obj)));
    }
   return List;
}

public CallDatabase(object)
{
    //Code to call DB 
}

All the objects received from the DB are independents.

After few research I am planning to use async calls, will this improve performance?

manthan davda
  • 319
  • 1
  • 3
  • 13
  • How would `async` help - don't you need to wait for the results to come back before you continue anyways? – D Stanley Oct 05 '15 at 14:30
  • No I don't have to wait for result. As soon as i get records from DB I will build object and add to list. Client will receive the list of the objects generated from DB. All objects are independent. – manthan davda Oct 05 '15 at 15:01

4 Answers4

3

I'm not sure it's going to make any difference either way. I assume you still need to wait for all results to be loaded, in which case async does not help, and your bottleneck will most likely be network I/O and server processing rather than local CPU, so parallelism will not help either.

That said, if you don't need the results of the query and don't care if there is an error, then async may help in a fire-and-forget scenario.

Your biggest bang for your buck may be to try and get multiple results in one query rather than firing off a bunch of individual queries.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • 1
    Aren't you making assumptions about architecture here? The database server might be a powerful machine, or part of a cluster, with the queries not being locked by each other, in which case you might see a performance increase by running the queries in parallel. – Ananke Oct 05 '15 at 14:42
  • Initial plan was to get everything in one DB call but that is not feasable given the complexity of the query,, – manthan davda Oct 05 '15 at 14:59
  • D Stanley, `WhenAll` let's you `await` many operations as shown in my post, but indeed it unlikely to speed things up if DB access is already maxes out usage of whatever resources (network, DB server,...). – Alexei Levenkov Oct 05 '15 at 15:04
  • @Ananke Yes I'm assuming that I/O is much more of a bottleneck than local CPU, which I think is reasonable, even in a clustered environment. Parallel only helps in CPU-intensive operations by taking advantage of multiple local cores. – D Stanley Oct 05 '15 at 15:12
1

Defintiely Async, as Parallel.ForEach is meant for compute intensive operations. It spreads over available core resources and orchestrates them accordingly. Async, instead, is meant for just this kind of operations: make a request to the service, go ahead and receive notification once resources requested before are available.

Tigran
  • 61,654
  • 8
  • 86
  • 123
  • Just out of curiosity, What happens if i use parllel foreach for my scenario.. Will it block the next item to call database until 1st is done? – manthan davda Oct 05 '15 at 14:28
  • No, it will block single thread, which will wait you DB call being complete. so your program will run smoothly, but using threads for these kind of things is a waste of resources. – Tigran Oct 05 '15 at 14:30
  • Parallel.ForEach is not ideal for IO bound operations because each thread will block, waiting for the data. If async operations are available for calling your database then it is better to make use of these. – Ananke Oct 05 '15 at 14:35
1

This is mostly comment to D Stanley's answer - switching to parallel/async code unlikely to improve performance.

If your main concern is responsiveness/scalability - async would be better as generally DB access is IO-bound operation. It also allows to pick between sequential and parallel processing (i.e. in case your DB layer does not support concurrent requests on same connection for some reason). Additionally with async it is easier to get synchronization right for updating UI/request if you use default synchronization context.

Sequential: it will run about as long as non-async solution, but the thread will be free to perform other activities at the same time (for UI applications like WinForms/WPF) or process requests (ASP.Net).

async public Task<ResultType> CallMethodAsync()
{
    foreach(var obj in input)
    {
        var singleResult = await CallDatabaseAsync(obj);
        // combine results if needed
    }
    // return combined results    
}

Parallel: will run all requests at the same time, will likely be faster than sequential solution.

async public Task<ResultType> CallMethodAsync()
{
    List<Task<SingleResultType>> tasks = new List<Task<SingleResultType>>();
    foreach(var obj in input)
    {
        tasks.Add(await CallDatabaseAsync(obj));
    }
    await Task.WhenAll(tasks);

    foreach(SingleResultType result in tasks.Select(t=>t.Result))
    {
        // combine results if needed
    }
    // return combined results    
}

Note that async generally requires all your code to be asynchronous - so if you converting just small piece of code to run in parallel Parallel.ForEach may be easier solution as it does not involve dealing with await vs Task.Wait - Deadlock?.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
0

I have implemented a solution; not sure if this async or will improve performance a bit or not, I am very new to async so don't have much idea.

 public static async Task<List<Response>> Execute(Request objInput)
 {
       List<Response> objList = new List<Response>();
       foreach (object obj in objInput.objs)
        {
            objList.Add(await Task.Run(() =>GetDataFromDB(obj)));
        }
  return objList;
 }


  private static object GetDataFromDB(object obj)
  {
       //Call DB and build the object
  }

If this is not the correct way to implement async, then please offer other ideas.

halfer
  • 19,824
  • 17
  • 99
  • 186
manthan davda
  • 319
  • 1
  • 3
  • 13
  • I would think you'd want your `GetDataFromDB` to also be `async` and then it should call `async` methods for communicating with the DB. Then you don't need the `Task.Run` in your `Execute` method. – juharr Oct 05 '15 at 15:34
  • I read somewhere that await (Task.Run) will call async. is that correct? – manthan davda Oct 05 '15 at 15:40
  • The idea of `async` is that something is doing IO and you want to free up threads while that IO occurs. When you use `await Task.Run` you are just pushing the "waiting" from one thread to another. – juharr Oct 05 '15 at 15:42
  • If you don't mind can you post one example of how to do that? this things are very confusing. – manthan davda Oct 05 '15 at 15:47