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.
Using context.MyEntity.ToList() keeps the current thread busy until the Database finishes the query execution.
Using await context.MyEntity.ToListAsync(); frees the current thread until the Database finishes the query execution.
Using await Task.Factory.StartNew(() => { }); frees the current thread, but creates a new thread, and keeps it busy until the DB finishes the execution.
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();
}
Related
After browsing different await vs Task.Run questions on SO my takeaway is that await is better for I/O operations and Task.Run for CPU-intensive operations. However the code with await seems to always be longer than Task.Run. Below is an example method of how I am creating a context object with await in my app:
public async AppContext CreateAppContext()
{
var context = new AppContext();
var customersTask = _dataAccess.GetCustomers();
var usersTask = _dataAccess.GetUsers();
var reportsTask = _dataAccess.GetReports();
context.Customers = await customersTask;
context.Users = await usersTask;
context.Reports = await reportsTask;
return context;
}
If I was to rewrite this with Task.Run I could do
public async AppContext CreateAppContext()
{
var context = new AppContext();
await Task.WhenAll(new[]
{
Task.Run(async () => { context.Customers = await _dataAccess.GetCustomers(); }),
Task.Run(async () => { context.Users = await _dataAccess.GetUsers(); }),
Task.Run(async () => { context.Reports = await _dataAccess.GetReports(); });
})
return context;
}
The difference is not major when I create an object with 3 properties but I have objects where I need to initialize 20+ properties in this manner which makes the await code a lot longer (nearly double) than Task.Run. Is there a way for me to initialize the object using await with code that is not a lot longer than what I can do with Task.Run?
Personally, I prefer an asynchronous factory pattern over that kind of code; but if you need to do concurrent asynchronous work like that multiple times, then you'll probably want to write your own helper method.
The BCL-provided WhenAll works best when either all tasks have no results, or when all tasks have the same type of result. One fairly common approach to help WhenAll work with different types of tasks is to return a tuple of results, which can then be deconstructed into different variables if desired. E.g.,
public static class TaskEx
{
public static async Task<(T1, T2, T3)> WhenAll<T1, T2, T3>(Task<T1> task1, Task<T2> task2, Task<T3> task3)
{
await Task.WhenAll(task1, task2, task3);
return (await task1, await task2, await task3);
}
}
// Usage
public async AppContext CreateAppContext()
{
var context = new AppContext();
(context.Customers, context.Users, conext.Reports) =
await TaskEx.WhenAll(
_dataAccess.GetCustomers(),
_dataAccess.GetUsers(),
_dataAccess.GetReports());
return context;
}
You can even define a tuple GetAwaiter extension method if you want, to make it more implicit:
// Usage
public async AppContext CreateAppContext()
{
var context = new AppContext();
(context.Customers, context.Users, conext.Reports) =
await (
_dataAccess.GetCustomers(),
_dataAccess.GetUsers(),
_dataAccess.GetReports());
return context;
}
There are a couple of disadvantages to these approaches, though. First, you have to define as many overloads as you need. Second, the multiple-assignment code is not very nice; it's fine for 2 or 3 properties, but would get ugly (IMO) if done for much more than that.
So I think what you really want is a custom delegate form of WhenAll. Something like this should work:
public static class TaskEx
{
public static async Task WhenAll(params Func<Task>[] tasks)
{
return Task.WhenAll(tasks.Select(action => action()));
}
}
// Usage
public async AppContext CreateAppContext()
{
var context = new AppContext();
await TaskEx.WhenAll(
async () => context.Customers = await _dataAccess.GetCustomers(),
async () => context.Users = await _dataAccess.GetUsers(),
async () => conext.Reports = await _dataAccess.GetReports());
return context;
}
Since this solution avoids dealing with the different result types entirely, multiple overloads aren't needed.
If you really want to keep your general pattern (which I'd avoid - it would be much better to do all the work and then assign all the results at the same time; look into the return value of Task.WhenAll), all you need is a simple helper method:
static async Task Assign<T>(Action<T> assignment, Func<Task<T>> getValue)
=> assignment(await getValue());
Then you can use it like this:
await Task.WhenAll
(
Assign(i => context.Customers = i, _dataAccess.GetCustomers),
Assign(i => context.Users = i, _dataAccess.GetUsers),
Assign(i => context.Reports = i, _dataAccess.GetReports)
);
There's many other ways to make this even simpler, but this is the most equivalent to your Task.Run code without having to involve another thread indirection just to do an assignment. It also avoids the very common mistake when you happen to use the wrong Task.Run overload and get a race condition (as Task.Run returns immediately instead of waiting for the result).
Also, you misunderstood the "await vs. Task.Run" thing. There's actually not that much difference between await and Task.Run in your code - mainly, it forces a thread switch (and a few other subtle things). The argument is against using Task.Run to run synchronous code; that wastes a thread waiting for a thing to complete, your code doesn't.
Do keep in mind that WhenAll comes with its own complications, though. While it does mean you don't have to worry about some of the tasks ending up unobserved (and not waited on!), it also means you have to completely rethink your exception handling, since you're going to get an AggregateException rather than anything more specific. If you're relying on error handling based on identifying exceptions, you need to be very careful. Usually, you don't want AggregateException to leak out of methods - it's very difficult to handle in a global manner; the only method that knows the possibilities of what can happen is the method that calls the WhenAll. Hopefully.
It's definitely a good idea to run parallel operations like this in a way that cannot produce dangerous and confusing side-effects. In your code, you either get a consistent object returned, or you get nothing - that's exactly the right approach. Be wary of this approach leaking into other contexts - it can get really hard to debug issues where randomly half of the operations succeed and other half fails :)
Is there a way for me to initialize the object using await with code that is not a lot longer than what I can do with Task.Run?
If you want to run all tasks in parallel - in short no, you cant shorten number of lines. Also note that those two snippets are not fully functionally equivalent - see Why should I prefer single await Task.WhenAll over multiple awaits.
You can simplify (and maybe even improve performance a bit) your Task.WhenAll approach by introducing a method which will await and assign. Something along these lines:
public async AppContext CreateAppContext()
{
var context = new AppContext();
await Task.WhenAll(
AwaitAndAssign(val => context.Customers = val, _dataAccess.GetCustomers()),
AwaitAndAssign(val => context.Users = val, _dataAccess.Users()),
AwaitAndAssign(val => context.Reports = val, _dataAccess.GetReports())
);
return context;
async Task AwaitAndAssign<T>(Action<T> assign, Task<T> valueTask) =>
assign(await valueTask);
}
What's the difference between a top-down flow (where top is an API action and down is a Db transaction) using the following two approaches.
A full async-await flow
async Task X()
{
await Y();
}
async Task Y()
{
await Z();
}
async Task Z()
{
await session.CommitAsync();
}
Only the top-level method uses async-await.
async Task X()
{
await Y();
}
Task Y()
{
Z();
return Task.CompletedTask;
}
Task Z()
{
session.CommitAsync();
return Task.CompletedTask;
}
while the async instructs that Y should be executed async, what happens to Z ?
Edit: the question changed. General async answer below
The following Z will simply not wait for CommitAsync before returning. It's a fire and forget situation.
Task Z()
{
session.CommitAsync();
return Task.CompletedTask;
}
In an api controller situation this means that the web request would return to client before the session is committed.
Let's note this cannot be done for methods that return data.
The 2nd note is that there is no benefit here from returning a Task, and the return type could be changed to void (which may or may not help you reason about it).
Origjnal answer, still relevant
Let's say that in ZRealAsync calls await db.(...).ToListAsync() and ZPretendAsync calls ToList() and then returns Task.CompletedTask.
The difference is that a thread that happens to call ZRealAsync can be used to do other things after the query is sent to the database, and a thread which calls ZPretendAsync will not be able to be used for anything else until the result is obtained from the database, it will just wait; even if X is marked async and uses await.
If your web controllers call ZPretendAsync then the system won't be able to handle more concurrent requests than there are threads available, even if X is marked async and uses the await keyword. With ZRealAsync n threads can service more than n concurrent requests. Async makes a real difference, but only if it's real.
I have 30 sub companies and every one has implemented their web service (with different technologies).
I need to implement a web service to aggregate them, for example, all the sub company web services have a web method with name GetUserPoint(int nationalCode) and I need to implement my web service that will call all of them and collect all of the responses (for example sum of points).
This is my base class:
public abstract class BaseClass
{ // all same attributes and methods
public long GetPoint(int nationalCode);
}
For each of sub companies web services, I implement a class that inherits this base class and define its own GetPoint method.
public class Company1
{
//implement own GetPoint method (call a web service).
}
to
public class CompanyN
{
//implement own GetPoint method (call a web service).
}
so, this is my web method:
[WebMethod]
public long MyCollector(string nationalCode)
{
BaseClass[] Clients = new BaseClass[] { new Company1(),//... ,new Company1()}
long Result = 0;
foreach (var item in Clients)
{
long ResultTemp = item.GetPoint(nationalCode);
Result += ResultTemp;
}
return Result;
}
OK, it works but it's so slow, because every sub companys web service is hosted on different servers (on the internet).
I can use parallel programing like this:(is this called parallel programing!?)
foreach (var item in Clients)
{
Tasks.Add(Task.Run(() =>
{
Result.AddRange(item.GetPoint(MasterLogId, mobileNumber));
}
}
I think parallel programing (and threading) isn't good for this solution, because my solution is IO bound (not CPU intensive)!
Call every external web service is so slow, am i right? Many thread that are pending to get response!
I think async programming is the best way but I am new to async programming and parallel programing.
What is the best way? (parallel.foreach - async TAP - async APM - async EAP -threading)
Please write for me an example.
It's refreshing to see someone who has done their homework.
First things first, as of .NET 4 (and this is still very much the case today) TAP is the preferred technology for async workflow in .NET. Tasks are easily composable, and for you to parallelise your web service calls is a breeze if they provide true Task<T>-returning APIs. For now you have "faked" it with Task.Run, and for the time being this may very well suffice for your purposes. Sure, your thread pool threads will spend a lot of time blocking, but if the server load isn't very high you could very well get away with it even if it's not the ideal thing to do.
You just need to fix a potential race condition in your code (more on that towards the end).
If you want to follow the best practices though, you go with true TAP. If your APIs provide Task-returning methods out of the box, that's easy. If not, it's not game over as APM and EAP can easily be converted to TAP. MSDN reference: https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110).aspx
I'll also include some conversion examples here.
APM (taken from another SO question):
MessageQueue does not provide a ReceiveAsync method, but we can get it to play ball via Task.Factory.FromAsync:
public static Task<Message> ReceiveAsync(this MessageQueue messageQueue)
{
return Task.Factory.FromAsync(messageQueue.BeginReceive(), messageQueue.EndPeek);
}
...
Message message = await messageQueue.ReceiveAsync().ConfigureAwait(false);
If your web service proxies have BeginXXX/EndXXX methods, this is the way to go.
EAP
Assume you have an old web service proxy derived from SoapHttpClientProtocol, with only event-based async methods. You can convert them to TAP as follows:
public Task<long> GetPointAsyncTask(this PointWebService webService, int nationalCode)
{
TaskCompletionSource<long> tcs = new TaskCompletionSource<long>();
webService.GetPointAsyncCompleted += (s, e) =>
{
if (e.Cancelled)
{
tcs.SetCanceled();
}
else if (e.Error != null)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(e.Result);
}
};
webService.GetPointAsync(nationalCode);
return tcs.Task;
}
...
using (PointWebService service = new PointWebService())
{
long point = await service.GetPointAsyncTask(123).ConfigureAwait(false);
}
Avoiding races when aggregating results
With regards to aggregating parallel results, your TAP loop code is almost right, but you need to avoid mutating shared state inside your Task bodies as they will likely execute in parallel. Shared state being Result in your case - which is some kind of collection. If this collection is not thread-safe (i.e. if it's a simple List<long>), then you have a race condition and you may get exceptions and/or dropped results on Add (I'm assuming AddRange in your code was a typo, but if not - the above still applies).
A simple async-friendly rewrite that fixes your race would look like this:
List<Task<long>> tasks = new List<Task<long>>();
foreach (BaseClass item in Clients) {
tasks.Add(item.GetPointAsync(MasterLogId, mobileNumber));
}
long[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
If you decide to be lazy and stick with the Task.Run solution for now, the corrected version will look like this:
List<Task<long>> tasks = new List<Task<long>>();
foreach (BaseClass item in Clients)
{
Task<long> dodgyThreadPoolTask = Task.Run(
() => item.GetPoint(MasterLogId, mobileNumber)
);
tasks.Add(dodgyThreadPoolTask);
}
long[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
You can create an async version of the GetPoint:
public abstract class BaseClass
{ // all same attributes and methods
public abstract long GetPoint(int nationalCode);
public async Task<long> GetPointAsync(int nationalCode)
{
return await GetPoint(nationalCode);
}
}
Then, collect the tasks for each client call. After that, execute all tasks using Task.WhenAll. This will execute them all in parallell. Also, as pointed out by Kirill, you can await the results of each task:
var tasks = Clients.Select(x => x.GetPointAsync(nationalCode));
long[] results = await Task.WhenAll(tasks);
If you do not want to make the aggregating method async, you can collect the results by calling .Result instead of awaiting, like so:
long[] results = Task.WhenAll(tasks).Result;
I have an ASP.NET MVC 4 program and I wrote the following code where I wanted to make the Results() method async:
public async Task<ActionResult> Results()
{
var result1 = SomeMethodAsync(1);
var result2 = SomeMethodAsync(2);
var result3 = SomeMethodAsync(3);
await Task.WhenAll(result1, result2, result3);
ViewBag.Result1 = result1;
ViewBag.Result2 = result2;
ViewBag.Result3 = result3;
return View()
}
public async Task<int> SomeMethodAsync(int i)
{
//do some logic
//make db call
return await Task.Run( () => DbCall(i));
}
public int DbCall(i)
{
//make db call
return valueFromDb;
}
Since I am not using Entityframework 6 I cannot make the DbCall() async. I was reading that its not a good idea to use Task.Run in ASP.NET projects since Task.Run will borrow a thread from the ASP.Net thread pool and therefore can cause queuing issues with large number of requests (as there will be lower number of available threads for processing incoming requests).
1) How can I make my method async without using Task.Run?
2) Is it better to make the method synchronous than using Task.Run ?
2) Is it better to make the method synchronous than using Task.Run ?
Yes.
In this case, since you don't have naturally-asynchronous APIs available from EF6, the next best solution is to just be synchronous.
Note that even if you did have asynchronous APIs, a single DbContext can only handle one operation at a time anyway. You'd have to create multiple contexts in order to run multiple simultaneous queries, and that can get complex.
In my data access layer I'm attempting to create methods with return types of Task.
I cannot get the return type from the entity framework to return Task<List<MYtype>>
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
}
Is the only way to make this run correctly is to format the code like so:
public async static Task<List<ILeaf>> GetLeafs(int doorID)
{
return await Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
The reason I was asking is because I would like to give the option to run async, or am I not understanding this correctly?
If I can just return a Task then on the calling end I could give the option to await if I wanted to run async, but if i wanted to run synchronously I would just call the method as normal.
If I'm returning a Task do I always have to include the async keyword in the method signature?
Am I thinking about this the wrong way? If I've got a return type of Task then the method has the option of being called async or synchronously?
But, if I have async and Task in the method signature then the method runs async no matter what?
Thanks!
So to answer the literal question asked, you can just do this:
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
return Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
That said, note that this isn't a particularly useful method. The idea of leveraging asynchronous programming is that you don't want to have a thread pool thread sitting there doing nothing but waiting on this IO operation. Ideally you'd leverage IO that is inherently asynchronous in nature; a method that itself naturally returns a task.
You aren't really providing value to consumers of your code by wrapping the blocking IO in a call to Task.Run. If they need that operation to be run in a background thread they can do so on their own, and then they'll know more precisely that it's not a naively asynchronous operation.
See Should I expose asynchronous wrappers for synchronous methods? for more information on the subject.
public static async Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
var result = db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
return await Task.FromResult(result);
}
}