Reputation: 11920
I am working on an ASP .NET MVC 5 application that requires me to use the Task objects that were introduced in .NET 4.0. I am browsing through a few links that give an overview of Task objects. However, I could use a bit of help to check if I am going in the right direction.
Here is the stub that is generated by Visual Studio:
public Task<MyAppUser> FindByNameAsync(string userName) {
throw new System.NotImplementedException();
}
I have written a method called mySearch() that searches through a list. I could use this function for my implementation:
public Task<MyAppUser> FindByNameAsync(string userName) {
MyAppUser val = mySearch(userName);
return Task<MyAppUser>.FromResult<MyAppUser>(val);
}
While this may work, I am thinking I am not really utilizing the Task paradigm properly. Perhaps I can write the code as follows:
public Task<MyAppUser> FindByNameAsync(string userName) {
return Task<MyAppUser>.Factory.StartNew(() => mySearch(userName));
}
As I understand, I am simply returning a delegate as a Task object which the ASP.NET engine will execute as needed.
Am I using the Task paradigm correctly?
Upvotes: 0
Views: 493
Reputation: 456887
@Luaan's answer is quite good. I just want to expound on a couple of principles for using async
on ASP.NET.
1) Use synchronous method signatures for synchronous work.
I'm not sure why VS is generating an asynchronous stub. Since your mySearch
just "searches through a list" (a synchronous operation), then your method should look like this instead:
public MyAppUser FindByName(string userName) {
return mySearch(userName);
}
2) Use async
/await
for asynchronous work (i.e., anything doing I/O). Do not use Task.Run
or (even worse) Task.Factory.StartNew
to fake asynchronous work within a request context.
For example, if you needed to search in a database (I/O), then that would be naturally asynchronous, and you should use the asynchronous APIs (e.g., EF6 has asynchronous queries):
public Task<MyAppUser> FindByNameAsync(string userName) {
return dbContext.Users.Where(x => x.Name == userName).FirstAsync();
}
If you're planning to have asynchronous APIs but for now you're just doing test/stub code, then you should use FromResult
:
public Task<MyAppUser> FindByNameAsync(string userName) {
return Task.FromResult(mySearch(userName));
}
Upvotes: 2
Reputation: 63772
Don't ever return a new Task
from an XXXAsync
method - that's almost the worst thing you can do. In your case, using Task.FromResult
is probably the best option (if you are indeed forced to use the XXXAsync
methods and if you really don't have asynchronous I/O for the search method). In a web application, it's better to do the whole thing synchronously rather than appearing asynchronous while still taking up a different thread.
The reasoning is simple - asynchronous methods are a great way to conserve resources. Asynchronous I/O doesn't require a thread, so you can afford to reuse the current thread for other work until the data is actually ready. In ASP.NET, the callback will be posted back to a ThreadPool
thread, so you've managed to increase your throughput essentially for free.
If you fake the asynchronous method by using Task.FromResult
, it's true that this is lost. However, unlike in WinForms or WPF, you're not freezing the GUI, so there's no point in masking the lacking asynchronicity by spawning a new thread.
When you do the faking by using TaskFactory.StartNew
or Task.Run
, you're only making things worse, essentially - it's true that you release the original thread as with proper async I/O, but you also claim a new thread from the ThreadPool
- so you're still blocking one thread, you just added a bunch of extra work for the plumbing.
Upvotes: 2