18

The latest EF tutorial that goes through how to use EF 6 with MVC 5 seems to lean towards using asych calls to the database like:

Department department = await db.Departments.FindAsync(id);

Is this the new standard/best practice?

I'm not sure what the benefit is for this style of development with ASP.NET MVC.

Can someone comment on this pattern, is this the new standard that MS is promoting?

Cœur
  • 32,421
  • 21
  • 173
  • 232
public static
  • 11,876
  • 26
  • 60
  • 83
  • 1
    This reminds me of an old joke: "Why does the EF 6 tutorial use asynchronous calls? Because it can." – Sergey Kalinichenko Aug 01 '14 at 18:57
  • 1
    I just find it strange, and it doesn't really mention anything about using asych/await calls. – public static Aug 01 '14 at 18:58
  • I'd like to see benchmarks to "prove" that point (as far as benchmarks can prove anything!). I'd venture to guess it might even be slower in terms of response times, but maybe more scalable. But for a basic CRUD application I don't think it really matters. – public static Aug 01 '14 at 19:17
  • Personally, I don't care for tutorials like this. I'd rather a tutorial be kept as simple as possible, at least at the beginning. Mixing Entity Framework with async / await, means a novice has to deal with trying to learn 2 things at once. – Bradley Uffner Mar 16 '18 at 15:08

3 Answers3

45

In order to decide whether to go async or sync, compare the benefits and costs:

Async:

  • Almost never exhaust the thread-pool with async (the circumstances would have to be extreme)
  • Pretty much arbitrary levels of concurrency (concurrent requests and operations)
  • Saves 1MB of memory per thread save
  • Safe intra-request concurrency thanks to the SynchronizationContext
  • Can increase throughput by low double-digit percentages for high-load cases due to reducing OS scheduling overhead. That said, almost no production app is under high CPU load because if it was it was close to unavailability (in case of a load spike the app starts dropping requests)

Sync:

  • Simpler code: await makes 99% of the cases (almost) as simple as synchronous code. That said, the 10+ async questions each day on Stack Overflow speak a different language. Edge cases arise when you deviate from the simple path. Also when using legacy libraries that, for example, require you to hand them a synchronous callback
  • Less work for coding and debugging
  • Profiler-friendly (You can profile the app or just pause the debugger and see what the app is doing right now. Not possible with async.)
  • Interoperates perfectly with legacy code and libraries

Choose async with ASP.NET if you are calling high-latency services. A web-service is likely to be high latency. An OLTP database is almost always low-latency.

Choose async if your application benefits from very high levels of concurrency (100+). Most applications do not have such high levels, or their back-end services would not sustain such an amount of load. No point in making the web app scale but overload the back-end. All systems in the call chain must benefit from a high degree of concurrency in order for async to be beneficial.

Typical high-latency services (good cases for async):

  • Web-services
  • Waiting (e.g. sleep)
  • Throttling (SemaphoreSlim, ...)
  • Some cloud-services (Azure)
  • Long-running queries to the database (e.g. reporting or ETL)

Typical low-latency services (good cases for sync):

  • Database calls: Most OLTP queries are low-latency because you can assume the database server to not be overloaded. No point in throwing 100s of concurrent queries at it. Doesn't make them complete any faster.
  • File system: The same as databases.

These are categorized by the typical case. All of these can be in the opposite category as well.

You can mix sync and async in the same app. Use async when it is at its sweet spot.

So why are Microsoft and the Entity Framework team promoting async usage? Here comes the subjective part of this answer: It might be Microsoft internal policy. They might anticipate EF usage in client apps (for which async is great). Or, they don't realize that async database calls are pretty much almost always a waste of developer's time without benefits. Most people don't realize this because async is the way to go these days.

François Maturel
  • 4,991
  • 6
  • 40
  • 47
usr
  • 162,013
  • 33
  • 219
  • 345
  • How does this effect unit of work? In EF 4/5 I was using unit of work pattern but in EF 6 it seems the article is saying you don't really need it. – public static Aug 01 '14 at 19:25
  • @valid_where_void this does not affect "unit of work" at all. Thanks to await you can pretty much make every algorithm you have async with minimal structural changes. If you post the article link I can comment specifically. – usr Aug 01 '14 at 19:28
  • 2
    @valid_where_void: using the unit of work pattern with EF has nothing to do with async vs sync. It's more that there's a new version of EF and with it new understanding and recommendations for patterns and processes. Unit of work / repository with EF, was *never* a good idea, the tutorials are just finally being updated to reflect that. – Chris Pratt Aug 01 '14 at 19:29
  • 2
    @usr: Two things: 1) It's not accurate to say "never" exhaust thread-pool. You very much can still exhaust the thread pool even if you do everything async. It just gives you a higher ceiling than sync. 2) Maybe "simpler code" was true as a benefit of sync pre-.NET 4.5, but with async/await it's almost stupidly simple to do async and doesn't really complicate the code at all. – Chris Pratt Aug 01 '14 at 19:31
  • @ChrisPratt I edited. Regarding simpler code: True for 99% of the cases. That said, the 10 async questions each day on Stack Overflow speak a different language. Edge cases arise when you deviate from the simple path. Also when using legacy libraries that, for example, require you to hand them a synchronous callback. – usr Aug 01 '14 at 19:35
  • One major push by Microsoft towards Async is for Windows 8 applications on mobile devices, where that model maximizes UI responsiveness while minimizing battery usage. But those concerns are generally not in the thoughts of most web developers. That being said, async does come into play for long running items that only do work on rare events (signal R); running different pieces in parallel, or long running network/db requests. – Greg Mar 09 '15 at 20:31
  • (See http://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx , http://hanselminutes.com/327/everything-net-programmers-know-about-asynchronous-programming-is-wrong ) – Greg Mar 09 '15 at 20:31
13

On ASP.NET, you should use asynchronous APIs for anything I/O-related, including database access and web service calls.

Using async allows ASP.NET to make maximum use of the thread pool, resulting in non-trivial scalability benefits.

Stephen Cleary
  • 376,315
  • 69
  • 600
  • 728
  • Non-trivial scalability benefits, *in case the database can handle hundreds of concurrent requests*. – usr Aug 01 '14 at 19:04
  • 5
    @usr as Stephen mentions, the scaling is in the thread pool. Even if not all pages of your website depend on the database, using async calls will free up threads to serve requests. The scaling benefits are definitely non-trivial. If you want to support hundred thousands of requests, of course you need to look at your database but that's not what he means in this situation. – Wouter de Kort Aug 01 '14 at 19:06
  • The thread-pool only limits scalability when we go into the hundreds of concurrent operations. You can only achieve meaningfully more throughput going async if the thread-pool would have been exhausted otherwise. I understand the benefits of async, but they do not come for free. You pay with development cost for them. It would be irrational to go async in every situation. – usr Aug 01 '14 at 19:10
  • 1
    @usr that is what sparked this question, it is a 'how to' tutorial and they are pushing asych down everyone's throats. I wanted to know if this is considered best practise or is it over-optimization. We have been doing sych. calls for years and for 99% of apps it is never an issue. – public static Aug 01 '14 at 19:14
  • 2
    @usr: Modern async is practically as easy as sync. And it does bring benefits even before the thread pool is exhausted: in particular, `async` scales *faster* than the thread pool can by itself due to its limited injection rate. So it's great for bursting traffic. – Stephen Cleary Aug 01 '14 at 19:24
  • 1
    @usr: while true that if you're getting like 10 hits per month on your site, async is indeed probably overkill, the idea is to integrate scalability from the start. Async isn't free, but it's also not *that* costly. And, the millisecond here or there that it may take longer to load a page will more than pay for itself when your site suddenly goes under heavy load unexpectedly (the "Digg-effect") and starts falling down because you did everything sync. – Chris Pratt Aug 01 '14 at 19:24
  • @StephenCleary I had a great experience with just increasing thread-pool limits to mad levels (especially the minimum counts). This was for a legacy app. I would have used await had it been available at the time. We were calling a web service taking 10s for some high-frequency calls. Sweet spot for async, and *still* the thread-pool could keep up. – usr Aug 01 '14 at 19:26
  • @ChrisPratt when Digg puts load on you, your *backend* will limit your throughput. Make your web app ready to serve 1000 concurrent requests but it doesn't help a database which has only a few CPU cores. They will just queue up and the site falls down. Async does not help here. – usr Aug 01 '14 at 19:29
  • 2
    @usr: You're making the [classic case against async DB calls on ASP.NET](http://blogs.msdn.com/b/rickandy/archive/2009/11/14/should-my-database-calls-be-asynchronous.aspx). That argument made a lot of sense when async was hard and there was a single SQL Server backend. These days, async is easy and backends more often than not are Azure SQL or scalable NoSQL, and that argument doesn't hold up as well. (It's still a valid argument; it's just a lot weaker these days). – Stephen Cleary Aug 01 '14 at 19:41
  • @StephenCleary true. For those cases I acknowledge the usefulness of async. Will edit that into my answer. – usr Aug 01 '14 at 19:42
4

Ideally, anything that involves a period of waiting should be done asynchronously. A database query typically must call out to a remote server, send the query, and then wait for the server to respond with the results. That makes it a prime candidate for async as that whole "wait for the server to respond" part is a variable you can't account for in your application.

Using async allows the web server to reuse the current thread to field other web requests while your code is waiting for the async operation to complete. When it completes, a thread is given back to your application to continue processing. If you run sync, then while you're waiting for the database or whatever other long running process, the thread deadlocks and is not available to the web server's pool. If you do this enough, the web server can potentially run out of available threads and must begin queuing further requests. Async mitigates this by freeing up threads when they're just hanging around waiting on something, increasing the potential load that your web server can handle.

Chris Pratt
  • 207,690
  • 31
  • 326
  • 382
  • 1
    Although your answer is a good one, you may want to point out that not 'anything that can take a while should be done asynchronously'. In a web application you should execute I/O tasks async, but not CPU bound work. Only if you want to run things in parallel you can split CPU bound work but you should still measure performance to make sure you're not using more threads than is worth it. – Wouter de Kort Aug 01 '14 at 19:08
  • True, you can't async CPU-bound work because it needs the thread to complete the work. However, I was trying to keep the answer simplistic. CPU-bound pretty much excludes "taking awhile" in most scenarios except complex scientific or financial analysis, which is even more rare in a *web* scenario (the web application almost assuredly won't being doing the complex analysis itself, but rather some service that it would interact with). But, your point is valid, nevertheless. – Chris Pratt Aug 01 '14 at 19:15
  • So did MS re-write all its libraries to make them truly asynchronous? Or is it just wrapping it in a asych block but under the covers it is all synchronous. – public static Aug 01 '14 at 19:15
  • I don't know about *all*. I actually just butted up with the rather annoying fact that you can't do async action filters still in MVC5. But, yes, ever since .NET 4.5 introduced the async/await combo, making the core libraries async-capable has been a priority. – Chris Pratt Aug 01 '14 at 19:17
  • @ChrisPratt: Unfortunately true. However, async filters are supported on WebApi today and will be supported on MVC on ASP.NET vNext. – Stephen Cleary Aug 01 '14 at 19:26