We're in the process of refactoring all, or a large portion of our .NET 4.6 MVC WebAPI controller methods to async methods.
This seems like it will work well for methods that have a lower level invocation of a method that is awaitable such as SQL command execution; however we are utilizing an in-memory distributed caching framework by Alachisoft called NCache (4.6 SP2 to be exact), which does not offer any truly asynchronous methods.
Would it be worth creating an async helper method that would expose a awaitable Task<object> return type?
Traditionally using the NCache API, you Get an object from cache by a Key in the following usage;
NCacheObject.Get(string);
The proposal is to create a helper method of the following;
protected static async Task<Object> GetAsync(string key, Cache nCache)
{
Task<Object> getTask = new Task<Object>(() => nCache.Get(key));
getTask.Start();
return await getTask.ConfigureAwait(false);
}
So that it would then allow full waterfall of async methods up to the entry controller method as such;
public static async Task<Tuple<List<SomeModel>, bool, string>> GetSomeModelList(string apiKey)
{
return newTuple<List<SomeModel>, bool, string>(await GetAsync("GetSomeModelKey", CacheInstance).ConfigureAwait(false), true, "Success message");
}
And finally the controller method;
[HttpGet, Route("Route/Method")]
public async Task<ResponseOutputModel<List<SomeModel>>> GetSomeModelList()
{
ResponseOutputModel<List<SomeModel>> resp = new ResponseOutputModel<List<SomeModel>>();
try
{
Tuple<List<SomeModel>, Boolean, String> asyncResp = await CacheProcessing.GetSomeModelList(GetApiKey()).ConfigureAwait(false);
resp.Response = asyncResp.Item1;
resp.Success = asyncResp.Item2;
resp.Message = asyncResp.Item3;
}
catch (Exception ex)
{
LoggingHelper.Write(ex);
resp.StatusCode = Enumerations.ApiResponseStatusCodes.ProcessingError;
resp.Success = false;
resp.Message = ex.Message;
}
return resp;
}
This would complicate the refactoring, as the original methods actually had output parameters for bool success and string message; but it seems this can be accomplished in a decent and quick manner using a Tuple<>; otherwise we could just create a return type model.
To do this properly, there would be many hundreds of methods to refactor; quite an undertaking.
Would this work as expected, and be the best solution to accomplish the objective?
Is it likely worth all of the effort required, with the end goal of increasing scalability and subsequently "performance" of the web servers?
Would it be worth creating an async helper method that would expose a awaitable Task return type?
Nope.
The proposal is to create a helper method of the following
This just queues in-memory work to the thread pool.
(Side note: The task constructor should never be used. Ever. If you need to queue work to the thread pool, use Task.Run instead of the task constructor with Start)
Would this work as expected, and be the best solution to accomplish the objective?
Is it likely worth all of the effort required, with the end goal of increasing scalability and subsequently "performance" of the web servers?
These are the same question. The objective is scalability; asynchrony is just one means to help you accomplish it.
Asynchrony assists scalability on ASP.NET because it frees up a thread that can process other requests. However, if you make methods that are asynchronous by using another thread, then that doesn't assist you at all. I call this "fake asynchrony" - these kinds of methods look asynchronous but they're really just synchronously running on the thread pool.
In contrast to true asynchrony, fake asynchrony will actually hurt your scalability.
As this is a memory cache and Im saying this out of any direct experience with NCache but experiences with other cache systems.
Yes, this would work of course. I'd rather opt for a response struct or a generic class that allows me to define my response type (if it's possible at all). Tuples are not bad, probably would be more performant if you opt for classes instead. But they are not easy on the eyes.
Now, when it comes to performance, there is one question though. Here's a cache server for you and you want fast read-write of course. Accessing a memcache should be easy. As you're directly accessing the memory here, from a performance point of view, it won't really give you much. Are you making sure your code is fully async and you're using the threadpool properly to make things alright? Yes, of course but all it would ever do is add an extra layer or work when you're accessing your cache.
And the moment you're going for async, please do make sure that your memory cache is thread safe. :)
Related
I have a Web API controller (ASP.NET Core 5). Some of my APIs are asynchronous and some of them not. My question is next: Is there any advantages of using public **Task<T>** WebApiMethod + Task.FromResult() in Web API controllers if my method is synchronous?
For example:
public Task<string> GetSomeData()
{
// some synchronous processing...
return Task.FromResult(result);
}
Should I turn the example code above to something like this?
public string GetSomeData()
{
// some synchronous processing...
return result;
}
If the api is doing synchronous work it should have a synchronous signature. it will make the readability and understanding of the function clearer to other developers and will prevent misunderstanding when reading this function again in the future.
In the future, if the method will need to be modified to have an asynchronous task to do, you can change the signature to have an asynchronous signature.
You should use synchronous methods if the work is synchronous.
Yet, you should use Task signatures if you use some form of caching (e.g. with the proxy pattern). Then, of course if you already did the expensive I/O work, use Task.FromResult to return the cached result, and return the I/O task if it has to be newly downloaded.
It shouldn't have much difference in the way it is executed. If you can make the processing part asynchronous then it would make some difference.
I have a simple synchronous method, looking like this:
public IEnumerable<Foo> MyMethod(Source src)
{
// returns a List of Oof objects from a web service
var oofs = src.LoadOofsAsync().Result;
foreach(var oof in oofs)
{
// transforms an Oof object to a Foo object
yield return Transform(oof);
}
}
Since the method is part of a web application, it is good to use all resources as effectively as possible. Therefore, I would like to change the method into an asynchronous one. The easiest option is to do something like this:
public async Task<IEnumerable<Foo>> MyMethodAsync(Source src)
{
var oofs = await src.LoadOofsAsync();
return oofs.Select(oof => Transform(oof));
}
I am not an expert on either async/await or IEnumerable. However, from what I understand, using this approach "kills" the benefits of IEnumerable, because the Task is awaited until the whole collection is loaded, thus omitting the "laziness" of the IEnumerable collection.
On other StackOverflow posts I have read several suggestions for using Rx.NET (or System.Reactive). Quickly browsing through the documentation I have read that IObservable<T> is their asynchronous alternative to IEnumerable<T>. However, using the naive approach and trying to type the following just did not work:
public async IObservable<Foo> MyMethodReactive(Source src)
{
var oofs = await src.LoadOofsAsync();
foreach(var oof in oofs)
{
yield return Transform(oof);
}
}
I got an compilation error, that IObservable<T> does implement neither GetEnumerator(), nor GetAwaiter() - thus it cannot use both yield and async. I have not read the documentation of Rx.NET deeper, so I am probably just using the library incorrectly. But I did not want to spend time learning a new framework to modify a single method.
With the new possibilities in C# 7 it is now possible to implement custom types. Thus I, theoretically, could implement an IAsyncEnumerable, which would define both GetEnumerator() and GetAwaiter() methods. However, from my previous experience, I remember an unsuccessful attempt to create a custom implementation of GetEnumerator()... I ended up with a simple List, hidden in a container.
Thus we have 4 possible approaches to solve the task:
Keep the code synchronous, but with IEnumerable
Change it to asynchronous, but wrap IEnumerable in a Task<T>
Learn and use Rx.NET (System.Reactive)
Create a custom IAsyncEnumerable with C# 7 features
What are the benefits and drawbacks of each of these attempts? Which of them has the most significant impact on resource utilization?
Keep the code synchronous, but with IEnumerable
Change it to asynchronous, but wrap IEnumerable in a Task
Learn and use Rx.NET (System.Reactive)
Create a custom IAsyncEnumerable with C# 7 features
What are the benefits and drawbacks of each of these attempts? Which
of them has the most significant impact on resource utilization?
In your situation, it sounds like the best option is Task<IEnumerable<T>>. Here's what where each option excels:
Synchronous code (or parallel synchronous code) excels when there is no I/O, but heavy CPU use. If you have I/O code waiting synchronously (like your first method implementation), the CPU is just burning cycles while waiting for the web service to respond doing nothing.
Task<IEnumerable<T>> is meant for when there is an I/O operation to fetch a collection. The thread running waiting for the I/O operation can then have something else scheduled on it while awaiting.
This sounds like your case.
Rx is best for push scenarios: Where there is data being 'pushed' to your code which you want to respond to. Common examples are applications that receive stock-market pricing data, or chat applications.
IAsyncEnumerable is meant for when you have a collection where each item will require or generate an async task. An example: Iterating over a collection of items and executing some sort of unique DB query for each one. If your Transform was in fact an I/O-bound async method, then this is probably more sensible.
So one of my colleagues was saying to me -
"Why would somebody want to call async RestAPIs with thread, Its not beneficial and in return it will create a separate thread for every request."
My scenario is-
public async Task<ApiResponse<ProductLookupDto>> GetProductsByValueOfTheDay()
{
string url = "http://domain.com?param=10120&isBasic=true"
var result = Task.Run(() => JsonConvert.DeserializeObject<ProductLookupDto>(SerializedResults.GET(url)));
return new ApiResponse<ProductLookupDto>()
{
Data = await result,
Message = "success"
};
}
So here I am using async with threading. I know it will create a separate thread for request. Which is my concern about the performance.
I want to know if some of my methods are called together and if reponse is async as I am doing now. Will the thread affect to performance?
keeping in mind where - response from rest call is too large.
Your friend actually is not really knowing what he talks about - a Task will NOT create a separate thread for every request. Rather the task scheduler will determine threads - and the standard uses the thread pool. Which means that threads are pre allocated and reused, especially if you schedule a LOT of tasks. Also threads are released while the request runs due to completion ports. Your colleague shows a serious lack of basics here.
I think your colleague is right to be concerned with that code, and you are right to say "it pretends to be async but not really". And Jon Skeet is right to point out that the real problem here lies with SerializedResults.GET. Whatever the implentation of that is exactly, it's clearly a blocking call, otherwise it would return a Task<string> (that can be awaited) instead of a string. Wrapping a synchronous call in Task.Run and calling it asynchronous is a common mistake. You haven't eliminated blocking at all, you've simply moved the blocking call to a different thread.
So to make this asynchronous, SerializedResults.GET needs to go. It should be replaced by a call that uses a truly asynchronous library like HttpClient. Since this is a JSON API (and I'm a little bit biased), I'll show you an example using my Flurl library, which is basically a wrapper around HttpClient and Json.NET that provides some convenience methods to cut down on the noise a bit:
public async Task<ApiResponse<ProductLookupDto>> GetProductsByValueOfTheDay()
{
string url = "http://domain.com?param=10120&isBasic=true";
var result = await url.GetJsonAsync<ProductLookupDto>();
return new ApiResponse<ProductLookupDto>()
{
Data = result,
Message = "success"
};
}
In this method:
private async List<stuff> GetData()
{
return await _appCache.GetAsync("SiteStructurePages",
() => _repository.GetSomeStuff());
}
is there any reason to keep it async? My code will execute in async manner just once, and all subsequent requests will use cache. Async spreads up to other parts of my application, that doesn't hit database, because lots of stuff is cached.
Edit:
My application is IIS website application.
is there any reason to keep it async?
That really depends on you. If you actually need to take advantage of asynchronous operations, which is being able to scale, then do keep it. Otherwise, if you don't, use a synchronous API. it's all up to you and what you actually make use of in your code base.
I understand the fact that you're worried about async methods going "all the way" and actually altering your entire code-base to become async. That's why you should do it as long as it's worth it.
Side note - you can slightly modify your code to save yourself the async state-machine generation:
private Task<List<stuff>> GetData()
{
return _appCache.GetAsync("SiteStructurePages",
() => _repository.GetSomeStuff());
}
If you can ensure that the call is quick and that it's not going to block a UI thread, then sure, you don't need Async on this one.
However, if such things are not in your control, then I would leave it asynchronous.
Recently I've developed doubts about the way I'm implementing the async-await pattern in my Web API projects. I've read that async-await should be "all the way" and that's what I've done. But it's all starting to seem redundant and I'm not sure that I'm doing this correctly. I've a got a controller that calls a repository and it calls a data access (entity framework 6) class - "async all the way". I've read a lot of conflicting stuff on this and would like to get it cleared-up.
EDIT: The referenced possible duplicate is a good post, but not specific enough for my needs. I included code to illustrate the problem. It seems really difficult to get a decisive answer on this. It would be nice if we could put async-await in one place and let .net handle the rest, but we can't. So, am I over doing it or is it not that simple.
Here's what I've got:
Controller:
public async Task<IHttpActionResult> GetMessages()
{
var result = await _messageRepository.GetMessagesAsync().ConfigureAwait(false);
return Ok(result);
}
Repository:
public async Task<List<string>> GetMessagesAsync()
{
return await _referralMessageData.GetMessagesAsync().ConfigureAwait(false);
}
Data:
public async Task<List<string>> GetMessagesAsync()
{
return await _context.Messages.Select(i => i.Message).ToListAsync().ConfigureAwait(false);
}
It would be nice if we could put async-await in one place and let .net handle the rest, but we can't. So, am I over doing it or is it not that simple.
It would be nice if it was simpler.
The sample repository and data code don't have much real logic in them (and none after the await), so they can be simplified to return the tasks directly, as other commenters have noted.
On a side note, the sample repository suffers from a common repository problem: doing nothing. If the rest of your real-world repository is similar, you might have one level of abstraction too many in your system. Note that Entity Framework is already a generic unit-of-work repository.
But regarding async and await in the general case, the code often has work to do after the await:
public async Task<IHttpActionResult> GetMessages()
{
var result = await _messageRepository.GetMessagesAsync();
return Ok(result);
}
Remember that async and await are just fancy syntax for hooking up callbacks. There isn't an easier way to express this method's logic asynchronously. There have been some experiments around, e.g., inferring await, but they have all been discarded at this point (I have a blog post describing why the async/await keywords have all the "cruft" that they do).
And this cruft is necessary for each method. Each method using async/await is establishing its own callback. If the callback isn't necessary, then the method can just return the task directly, avoiding async/await. Other asynchronous systems (e.g., promises in JavaScript) have the same restriction: they have to be asynchronous all the way.
It's possible - conceptually - to define a system in which any blocking operation would yield the thread automatically. My foremost argument against a system like this is that it would have implicit reentrancy. Particularly when considering third-party library changes, an auto-yielding system would be unmaintainable IMO. It's far better to have the asynchrony of an API explicit in its signature (i.e., if it returns Task, then it's asynchronous).
Now, #usr makes a good point that maybe you don't need asynchrony at all. That's almost certainly true if, e.g., your Entity Framework code is querying a single instance of SQL Server. This is because the primary benefit of async on ASP.NET is scalability, and if you don't need scalability (of the ASP.NET portion), then you don't need asynchrony. See the "not a silver bullet" section in my MSDN article on async ASP.NET.
However, I think there's also an argument to be made for "natural APIs". If an operation is naturally asynchronous (e.g., I/O-based), then its most natural API is an asynchronous API. Conversely, naturally synchronous operations (e.g., CPU-based) are most naturally represented as synchronous APIs. The natural API argument is strongest for libraries - if your repository / data access layer was its own dll intended to be reused in other (possibly desktop or mobile) applications, then it should definitely be an asynchronous API. But if (as is more likely the case) it is specific to this ASP.NET application which does not need to scale, then there's no specific need to make the API either asynchronous or synchronous.
But there's a good two-pronged counter-argument regarding developer experience. Many developers don't know their way around async at all; would a code maintainer be likely to mess it up? The other prong of that argument is that the libraries and tooling around async are still coming up to speed. Most notable is the lack of a causality stack when there are exceptions to trace down (on a side note, I wrote a library that helps with this). Furthermore, parts of ASP.NET are not async-compatible - most notably, MVC filters and child actions (they are fixing both of those with ASP.NET vNext). And ASP.NET has different behavior regarding timeouts and thread aborts for asynchronous handlers - adding yet a little more to the async learning curve.
Of course, the counter-counter argument would be that the proper response to behind-the-times developers is to train them, not restrict the technologies available.
In short:
The proper way to do async is "all the way". This is especially true on ASP.NET, and it's not likely to change anytime soon.
Whether async is appropriate, or helpful, is up to you and your application's scenario.
public async Task<List<string>> GetMessagesAsync()
{
return await _referralMessageData.GetMessagesAsync().ConfigureAwait(false);
}
public async Task<List<string>> GetMessagesAsync()
{
return await _context.Messages.Select(i => i.Message).ToListAsync().ConfigureAwait(false);
}
If the only calls you do to asynchronous methods are tail-calls, then you don't really need to await:
public Task<List<string>> GetMessagesAsync()
{
return _referralMessageData.GetMessagesAsync();
}
public Task<List<string>> GetMessagesAsync()
{
return _context.Messages.Select(i => i.Message).ToListAsync();
}
About the only thing you lose is some stack-trace information, but that's rarely all that useful. Remove the await then instead of generating a state-machine that handles the waiting you just pass back the task produced by the called method up to the calling method, and the calling method can await on that.
The methods can also sometimes be inlined now, or perhaps have tail-call optimisation done on them.
I'd even go so far as to turn non-task-based paths into task-based if it was relatively simple to do so:
public async Task<List<string>> GetMeesagesAsync()
{
if(messageCache != null)
return messageCache;
return await _referralMessageData.GetMessagesAsync().ConfigureAwait(false);
}
Becomes:
public Task<List<string>> GetMeesagesAsync()
{
if(messageCache != null)
return Task.FromResult(messageCache);
return _referralMessageData.GetMessagesAsync();
}
However, if at any point you need the results of a task to do further work, then awaiting is the way to go.