Juan Pablo Gomez Juan Pablo Gomez - 28 days ago 8
C# Question

Async expressions C#

I'm trying to generate a repository with some methods and including Async versions for those ones, like this:

//Method 1
public static List<MyEntity> GetMyEntityByDate(MyContextType context)
{
var tmpMov = context.MyEntity
.AsNoTracking()
.ToList();

return tmpMov;

}

//Method 2 V1
public async static List<MyEntity> GetMyEntityByDateAsync(MyContextType context)
{
var tmpMov = await context.MyEntity
.AsNoTracking()
.ToListAsync();

return tmpMov;
}

//Method 2 V2
public async static List<MyEntity> GetMyEntityByDateAsync(MyContextType context)
{
List<MyEntity> tmpMov = null;
await Task.Factory.StartNew(() => {
tmpMov = GetMyEntityByDate(context);
});

return tmpMov;
}


Now I have some questions:

What are the pros and cons of using Method 2 V1 vs Method2 V2, in terms of performance and fluency?

Before someone downvote this question, YES I'm implementing a repository pattern and want to write less code, thats why I'm considering V2, that way I have only one query to maintain.

But I have poor experience on async and obiously my target is get The best possible performance.

Answer

What are the pros and cons of using Method 2 V1 vs Method2 V2, in terms of performance and fluency?

Method 2 V1 is a proper asynchronous method. Method 2 V2 is a fake-asynchronous method that executes blocking work on TaskScheduler.Current (which would be the thread pool if there is no current task scheduler).

As such, V2 runs afoul of the best practice not to expose asynchronous wrappers for synchronous methods.

Before someone downvote this question, YES I'm implementing a repository pattern and want to write less code, thats why I'm considering V2, that way I have only one query to maintain.

I'd say that the ideal scenario is to actually only expose Method 2 V1, and get rid of Method 1 completely. Querying a database is inherently I/O-based, so the API is naturally asynchronous.

If you really need both synchronous and asynchronous APIs, then I recommend using the "bool argument hack" as described in my MSDN article on Brownfield Async Development.

This could look like:

private async static Task<List<MyEntity>> DoGetMyEntityByDateAsync(MyContextType context, bool sync)
{
  var query = context.MyEntity
      .AsNoTracking();
  return sync ?
      query.ToList() :
      await query.ToListAsync();
}

public static Task<List<MyEntity>> GetMyEntityByDateAsync(MyContextType context)
{
  return DoGetMyEntityByDateAsync(context, sync: false);
}

public static List<MyEntity> GetMyEntityByDate(MyContextType context)
{
  return DoGetMyEntityByDateAsync(context, sync: true).GetAwaiter().GetResult();
}
Comments