0

I am trying to speed up some code of mine,

I make 2 or 3 reads to a slow database, and I want to make these calls run in paralle.

FSKWebInterfaceEntities dbSrc = new FSKWebInterfaceEntities();

public void main()
{     
 var TaskUsr = GetUserAsync(dev);
 var TaskOldCompany = GetOldCompanyAsync(dev);
 await Task.WhenAll();

 var usr = TaskUsr.Result;
 var oldCompanyName = TaskOldCompany.Result;
 ..... 
 use my two variables to insert a new entry into my localdb
}


    private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
    {
        return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
    }

    private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
    {
        return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
    }

On my two helper methods its is underlined green and said that there is no await, and therefore will run synchronously. However I cant return return await dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);

How should I modify my code to make the two reads in parallel?

pravprab
  • 2,301
  • 3
  • 26
  • 43
Zapnologica
  • 22,170
  • 44
  • 158
  • 253

2 Answers2

0

You can await that line because it is not an async method. You can't really await database calls as they are not thread safe. See this thread for an example of a way to do it, and a better explanation as to why not. You can consider using SqlCommands that have async methods as well.

Community
  • 1
  • 1
KJ3
  • 5,168
  • 4
  • 33
  • 53
0

You cannot use the same EF DbContext concurrently. From the EF Team's statement about thread safety:

For the moment, EF will detect if the developer attempts to execute two async operations at one time and throw.

You still can call them asynchronously, but sequentially:

public async Task main()
{     
 var sr = await GetUserAsync(dev);
 var oldCompany = await GetOldCompanyAsync(dev);
 ..... 
 use my two variables to insert a new entry into my localdb
}

Updated to address the comment:

Could you possible post a simple example of how I would change my above code to use the multiple dbcontext, As I don't really know the correct way to do it, I would be coding in the dark.

Something like below. I'm not an expert in EF to assure you this will actually improve the processing time. There may be significant overhead of opening the database connection for each context.

public async Task main()
{     
 var TaskUsr = GetUserAsync(dev);
 var TaskOldCompany = GetOldCompanyAsync(dev);
 await Task.WhenAll(TaskUsr, TaskOldCompany);

 var usr = TaskUsr.Result;
 var oldCompanyName = TaskOldCompany.Result;
 ..... 
 use my two variables to insert a new entry into my localdb
}

private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
 using (var dbSrc = new FSKWebInterfaceEntities())
  return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}

private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
 using (var dbSrc = new FSKWebInterfaceEntities())
  return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • So I can do that, But it wont actually help me speed up the procedure As it still runs sequentially? – Zapnologica Mar 26 '14 at 07:08
  • @Zapnologica correct, so if you want multiple calls you need multiple instances of your DbContext, perhaps create a new context inside the function instead of having a global shared one (be sure you use a `using` block to dispose it) – Scott Chamberlain Mar 26 '14 at 07:11
  • @Zapnologica, correct, it would only help your code to scale better, if it's web app or a WCF service. To run it in parallel, try using separate `DbContext` objects for each task, as suggested by @TomTom and Scott Chamberlain. – noseratio Mar 26 '14 at 07:12
  • Im sure I ahe tried using separate dbcontext and it threw an error saying that a dbcontext has already been instantiated. – Zapnologica Mar 26 '14 at 07:13
  • 1
    @Zapnologica, show the code where you tried that and it threw. – noseratio Mar 26 '14 at 07:14
  • Could you possible post a simple example of how I would change my above code to use the multiple dbcontext, As I don't really know the correct way to do it, I would be coding in the dark. – Zapnologica Mar 26 '14 at 07:23
  • I did notice that in visual studio it suggest I use `await Task.Run` Would this work better than calling the await before the function call? Btw I made my changes to use the dbcontext and it has not given me any errors yet. – Zapnologica Mar 26 '14 at 11:24
  • @Zapnologica, no. It might only make sense to wrap an async method with `Task.Run` if at the beginning of the async method there's a lengthy blocking operation (e.g., DNS resolution). Even then, it would makes sense for a UI app where it would freeze the UI, but not for a web app. – noseratio Mar 26 '14 at 11:27