CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Forum has moved

New location: CSLA .NET forum


CSLA .NET Resources:
  • CSLA .NET forum
  • CSLA .NET home page
  • How much async is too much?

    rated by 0 users
    Not Answered This post has 0 verified answers | 3 Replies | 2 Followers

    Top 500 Contributor
    21 Posts
    Brad Rem posted on Fri, Feb 7 2014 9:23 AM

    For an ASP.NET MVC application I'm wondering how much is too much. Here's some example code that I've tried to make as async as possible.

    For MVC, at what point is async not doing us any favors?

    Drilling down from the Controller action:

    public async Task<ActionResult> DetailsAsync(int id)
    {
      ViewData.Model = await ProjectEdit.GetProjectAsync(id);
      return View();
    }
    

    CSLA business object and DAL:

    public static async Task<ProjectEdit> GetProjectAsync(int id)
    {
      return await DataPortal.FetchAsync<ProjectEdit>(id);
    }
    
    private async Task DataPortal_FetchAsync(int id)
    {
      using (var ctx = ProjectTracker.Dal.DalFactory.GetManager())
      {
        var dal = ctx.GetProvider<ProjectTracker.Dal.IProjectDal>();
        var data = await dal.FetchAsync(id);
        using (BypassPropertyChecks)
        {
            id = data.Id;
            //....
        }
      }
    }
    
    public async Task<ProjectDto> FetchAsync(int id)
    {
      using (var ctx = ObjectContextManager<PTrackerEntities>.GetManager("PTrackerEntities"))
      {
        var result = from r in ctx.ObjectContext.Projects
                     where r.ProjectId == id
                     select new ProjectDto
                     {
                       ProjectId = r.ProjectId
                     };
        return await result.FirstAsync();
      }
    }
    

    All Replies

    Top 10 Contributor
    9,475 Posts

    Remember that async usually does NOT mean multiple threads. It means concurrent IO.

    What you get from concurrent IO on a web server is really two things.

    First, the web server gets to reuse your thread when you code gets blocked by IO - at least that's my understanding. This improves the overall scalability of the server, but does nothing for your particular web request.

    Second, IF you are doing multiple concurrent IO requests, and IF you structure your code to make those requests concurrently, then your web request might gain some performance because the IO requests are concurrent instead of sequential.

    If you do this:

    var a = await obi.Request1();
    var b = await obi.Request2();

    Then you get nothing, because these requests will be "async", but sequential. So what you need to do is something like this (from memory, so might not be perfect):

    var tasks = new List<Task>();
    tasks.Add(obj.Request1());
    tasks.Add(obj.Request2());
    await Tasks.WaitAll(tasks);

    It is something like that anyway - basically get the Task objects from the methods you want to run concurrently, then use a wait statement so you can await the completion of all the tasks in the list. 

    Rocky

    Top 500 Contributor
    21 Posts

    What my question really asks is how deep do we take the async and can we end up penalizing ourselves?

    I understand (or think I do) how web requests work.  I envision it like a sort-of-fast food restaurant:

    Customers arrive at the counter and ask a Worker for food (let's just call the stuff fast-food produces "food"). The Worker brings the Customer food.

    So, a Customer arrives and asks for Fries. The Worker goes over the Fry station and drops a basket of Fries into the boiling oil.  In a synchronous scenario, the Worker would remain at the Fry station until the Fries were done. What's bad about this is that you have Customers queuing up at the counter with nobody to serve them.

    But, in the asynchronous model, the Worker would drop the Fries into the oil, set the timer alarm, and return back to the counter to take another order. While the Fries are cooking, they could take an order for a drink or an ice cream or something like that, completing the order for several customers. When the Fries are done and the alarm goes off, a free Worker goes gets the Fries and gives them to the customer that originally asked for them.

    If we modeled that in MVC with CSLA:

     
    // the controller action
    public async Task<ActionResult> GetFries()
    {
       var fries = await Fries.GetCollectionAsync();

        return View(new FryModel(fries));
    }

    // the code in the CSLA business class
    public static async Task<Fries> GetCollectionAsync()
    {
      return await DataPortal.FetchAsync<Fries>();
    }

    If a Customer makes a web request to GetFries(), thanks to our await, we free up the request thread so it can handle other requests while the IO of the CSLA object is happening. 

    And now we're just getting to the kernel of my question.  In this mythical Fries CSLA collection, what would the difference of these two DataPortal_Fetch methods be if you consider the above code?

    private void DataPortal_Fetch()
    {
      using (var ctx = FastFood.Dal.DalFactory.GetManager())
      {
        var dal = ctx.GetProvider<FastFood.Dal.IFryDal>();
        var rows = dal.Fetch();
        foreach (var row in rows)
        {
            Add(Fry.GetChild(row));
        }
      }
    }

    ---- or ------

    private async Task DataPortal_FetchAsync()
    {
      using (var ctx = FastFood.Dal.DalFactory.GetManager())
      {
        var dal = ctx.GetProvider<FastFood.Dal.IFryDal>();
        var rows = await dal.FetchAsync();
        foreach (var row in rows)
        {
            Add(Fry.GetChild(row));
        }
      }
    }

    The first DataPortal_Fetch does not contain any asynchronous calls, but the second DataPortal_Async awaits the call to the DAL where you can presume that there are some async calls with Entity Framework fetching from a SQL server.

    I should ask, though, Is it true that I could interchangability use either of the two above DataPortal Fetch methods with this calling code:
       
        // this will either work with DataPortal_Fetch or DataPortal_FetchAsync, right?
        await DataPortal.FetchAsync<FryList>();

    What I'm driving at is that in regards to ASP.NET, I don't see any real difference between making the DAL asynchronous.

    Said another way, AFTER you call "await DataPortal.FetchAsync<FryList>()", does it even matter if the DataPortal_Fetch or the calls to the ORM are synchronous or asynchronous? 

    I'm tending to believe that after you call "await DataPortal.FetchAsync" it no longer matters if the methods deeper than that call contain asynchronous calls.

    Top 10 Contributor
    9,475 Posts

    It is _very_ important to understand that async doesn't mean parallel. It might, but it might not, and usually it doesn't.

    Using the async/await keywords usually does _not_ result in a background thread running a background task. Usually what happens is that it results in a blocking IO operation and your original (and only) thread is able to do some other work until the IO operation completes. In ASP.NET that thread may not even be working for you, it might be servicing some other request.

    So on a web server using async helps the scalability of the server as a whole, not necessarily your app.

    On a smart client the same thing is generally true - usually blocking IO - but the benefit there is that the UI remains responsive to the user - that's what the would-be-idle thread is doing is processing the Windows message queue.

    Now if you actually create a thread (Task.Run or something) then async really is parallel in that you have multiple CPU activities running at once. That's not what normally happens though, because most of the libraries you call are doing IO at some level, not spinning up new threads.

    Rocky

    Page 1 of 1 (4 items) | RSS

    Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
    Email admin@lhotka.net for support.
    Powered by Community Server (Non-Commercial Edition), by Telligent Systems