I explored memory leaking problem with my ASP .NET app when uploading files to server. For this purpose I wrote a very easy controller with two methods:
[ApiController]
[Route("[controller]")]
public class MoqController : ControllerBase
{
[HttpPost()]
[Route("UploadString")]
public async Task<IActionResult> UploadStringAsync(string str)
{
return Ok(str);
}
[HttpPost()]
[Route("UploadFile")]
public async Task<IActionResult> UploadFileAsync(IFormFile uploadedFile)
{
return Ok();
}
}
Invoking the UploadFileAsync method via Swagger increases the memory used by the application, and the garbage collector does not clear it. Memory consumption increases by 1-3 megabytes for each query and is weakly dependent on file size.
Calling the UploadStringAsync method does not seem to lead to this behavior
What is the reason of such behavior and how it might be changed?
Related
I have an ASP.NET Core 3.1 based project written using C#. I am aware that the best time to use await and async is when accessing external resources like pulling data from the database, accessing files, or making an HTTP request. This frees up the thread so more work is done instead for the thread to sit around waiting for code to finish.
However, I am trying to figure out at what point using async/await will hurt performance? Does the process of releasing the thread when await is called and retrieving a thread when the task complete have cost?
The code found next, is called asynchronously. In reality, that code does not need to be called asynchronously since all the code is executed in memory and no external requests are made.
public interface ILocator
{
Task<Model> ExampleAsync();
}
public class Example : Controller
{
public ILocator Locator { get; set; }
public Example(ILocator locator)
{
Locator = locator;
}
public async Task<IActionResult> Example()
{
Model model = await Locator.ExampleAsync();
return View(model);
}
}
public class Locator : ILocator
{
pubilc Task ExampleAsync()
{
Example model = new Example();
model.Status = "New";
return Task.CompletedTask;
}
}
Here is the synchronous version of the above code
public interface ILocator
{
Model Example();
}
public class Example : Controller
{
public ILocator Locator { get; set; }
public Example(ILocator locator)
{
Locator = locator;
}
public IActionResult Example()
{
Model model = Locator.Example();
return View(model);
}
}
public class Locator : ILocator
{
pubilc Example()
{
Example model = new Example();
model.Status = "New";
}
}
Will the asynchronous version of the code have higher cost/lower performance than the synchronous version due to the unnecessary await/async usage?
When will async/await do more harm than good?
You typically use async/await when performing I/O bound tasks like reading from a stream, reading from a DB, sending something over the network or waiting for a response.
This makes the thread available to do some other (CPU related work).
Technically, async/await is slower in terms of raw performance, however, it increases the scalability of your application since it allows threads to be available for other work while others are waiting for I/O bound operations.
I have an ASP.NET Core 3.1 based project written using C#.
That means that async/await will allow you to increase your capacity (in requests pers second) a great deal.
at what point using async/await will hurt performance?
it will add a little bit of overhead that is a fixed amount. It will in general be small compared to the costs of the I/O and not really noticable.
When will async/await do more harm than good?
In a web site/service that will never see a load above ~50 requests / second.
And even then the 'harm' will be very small.
Actual numbers depend on the hardware, amount of I/O work etc.
In reality, that code does not need to be called asynchronously since all the code is executed in memory
In that case it will be faster to handle it synchronously.
But I know teams that prefer to have all Actions async, just for uniformity. And since the overhead is so small I consider that a valid approach too.
I hope this is still on-topic. In this post here I saw how to create an await ViewAsync():
Returning a view with async keyword
So my consideration was: okay, I want to make my application use multithreading, let's make a BaseController that contains those methods for ViewAsync:
just a part of it:
public class BaseController : Controller
{
[NonAction]
public virtual async Task<ViewResult> ViewAsync()
{
return await Task.Run(() => this.View(null));
}
[NonAction]
public virtual async Task<ViewResult> ViewAsync(string viewName)
{
return await Task.Run(() => this.View(viewName, this.ViewData.Model));
}
// the other implementations....
}
now I could always call like this in the inheriting class:
[HttpGet]
public async Task<IActionResult> DoSomething()
{
// maybe we need to do something here, maybe not
return await ViewAsync(new DoSomethingObject());
}
imho, my advantage/target is performance since I always can use multithreading now.
Am I right with my consideration?
In the post, a comment to an answer started with I wouldn't do this. But there aren't many votes/comments/answers.. Where are risks or disadvantages of such an implementation? And maybe, why doesn't Microsoft.AspNetCore.Mvc.Controller come with the method ViewAsync?
Any web app already uses multithreading. When a request comes in, a thread from the thread pool handles it. Your app already handles multiple requests at the same time, without you using Task.Run.
Async/await stuff is useful so that you don't block threads from the thread pool while you wait for async operations to complete (like querying a DB).
Starting new tasks Task.Run on the default thread pool is pretty much useless, unless you are doing some CPU intensive work. Let's say you have an endpoint that calculates the prime numbers up to n on each request, in that case you could delegate a new task on the default thread pool that returns the prime numbers, and have a view that renders them to some html.
Rendering a view has nothing asynchronous about it, so a ViewAsync is not needed. Preparing the data for a view probably is async, but the rendering is not. Also, having a ViewAsync would probably over complicate the template syntax.
Let's say I have a method calling Mongodb database via .net mongo driver (below-mentioned Collection object is part of its Api):
public virtual Task<List<T>> GetAllAsync()
{
return Collection.Find(Filter.Empty).ToListAsync();
}
Now I have an async asp.net controller where I want to call this method from. However this example runs into thread deadlock issue, which results in current asp.net thread hangs:
public class TestController : AsyncController
{
[HttpGet]
public async Task<ActionResult> TestAction()
{
var data = await GetAllAsync<Client>();
...
}
}
While this example works fine:
public class TestController : AsyncController
{
[HttpGet]
public async Task<ActionResult> TestAction()
{
var data = await GetAllAsync<Client>().ConfigureAwait(false);
...
}
}
the only difference is ConfigureAwait(false) in the latter example.
Should I add this ConfigureAwait(false) everywhere in situations like this, or there is a more elegant solution to the problem?
UPDATE:
If I create MVC project from scratch same action methods work fine not getting into deadlock issue. Though if I use old MVC project that I migrated into new MVC, the problem with deadlock occur in the first example. Not sure what the difference is between this two, I opened packaged.config and bin directory and made sure same versions of Microsoft.AspNet.* are used, C# code is the same. The only thing different is old solution has things like StructureMap and Cassette preinstalled, could be some different settings in web.config impacting controller behavior as well.
ConfigureAwait(false) cannot be used on action methods because the execution must return to the synchronization context after the await.
On any other method ConfigureAwait(false) should be used.
If some code is synchronously blocking in an asynchronous method, the whole thing will block.
I want to run a method asynchronously from my web api code but I am not getting the desired behavior.
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
I have tried various combination of calls with await and async but not getting any success still.
I might not be understanding the concept of async/await correctly.
Can you please let me know what's the mistake I am making?
My controller code is below
[HttpGet("{id}")]
public string Get(int id)
{
PracticeAsync p = new PracticeAsync();
p.LongCallMethod();
return "Success";
}
The code for the class PracticeAsync is below:
public class PracticeAsync
{
public async Task LongCallMethod()
{
var x = await CallThis();
}
public async Task<dynamic> CallThis()
{
Thread.Sleep(10000); //DB call
return "done";
}
}
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
That's not how async works.
You'll need to use SignalR or a proper distributed architecture. Specifically, your webapp should place its work into a reliable queue, and have an independent service read from that queue and do the work. ASP.NET was designed to serve web requests, and has severe reliability limitations if you try to force it to do otherwise.
I'm trying to convert some methods to async and have started off with a simple example within the controller I am modifying:
public class MyAPIController : AsyncController
{
public async Task<JsonResult> List()
{
return Json(123456, JsonRequestBehavior.AllowGet);
}
...
}
When I test the method rather than the Json result I get the string value "System.Threading.Tasks.Task`1[System.Web.Mvc.JsonResult]" which I have verified with Fiddler and by browsing.
The project has been manually upgraded to .NET45. Searches suggest that this is possibly a problem with incorrect assembly versions but a check of the project file and Process view suggests that the correct types are referenced and loaded at run time.
Does anyone have any debugging tips for this?
Thanks.
After stripping out 90% of the code to get it working and gradually adding it back in until it failed it turns out that a custom ControllerActionInvoker was being used. The fix was to change the custom invoker to inherit from AsyncControllerActionInvoker and override BeginInvokeAction instead of InvokeAction. AsyncControllerActionInvoker can handle both Async and sync methods.