none
Await-async seems costly to me RRS feed

  • Question


  • I can see the value of running three db queries simultaneously using Task.WhenAll.

    But typically when a user does an Ajax postback from a browser to an MVC controller, I only need to run one db query at a time, or even in total. 
    await dbContext.Products.FindAsync(productId);
    In such cases, isn't the context-switch a needless cost? Why not simply run the query on the current thread? I mean, the current thread isn't really doing anything anyway, is it? Isn't it merely  waiting for the await to complete? So why not put it to good use? (Certainly if it were a winforms app, the current thread (i.e. the UI thread) would already have something to do, as it would be busy listening for, and reacting to, user-clicks). 
    Monday, December 4, 2017 1:29 AM

Answers

  • ASP.NET applications that runs in the same application pool shares threads in thread pool of the same worker process (usually the w3wp.exe now). Therefore you normally won't like request handlers holding precious thread resources for extensive time.
    • Marked as answer by jal2 Monday, December 4, 2017 4:41 AM
    Monday, December 4, 2017 1:55 AM
    Answerer
  • Sorry for not making my point clear here.

    The thing that actually matter is "the threads in active state". When you're doing async call, the thread it is running on is temporarily put into sleep therefore not holding CPU resources.

    And yes, unless you do expect your query return lots of data that it'll need more than 1 second to return, you don't really gain performance benefit by doing it async way. (In my ex-company, it's only added for long queries and I don't bother convert code to async calls for everything)

    • Marked as answer by jal2 Monday, December 4, 2017 4:41 AM
    Monday, December 4, 2017 3:13 AM
    Answerer

All replies

  • ASP.NET applications that runs in the same application pool shares threads in thread pool of the same worker process (usually the w3wp.exe now). Therefore you normally won't like request handlers holding precious thread resources for extensive time.
    • Marked as answer by jal2 Monday, December 4, 2017 4:41 AM
    Monday, December 4, 2017 1:55 AM
    Answerer
  • ASP.NET applications that runs in the same application pool shares threads in thread pool of the same worker process (usually the w3wp.exe now). Therefore you normally won't like request handlers holding precious thread resources for extensive time.

    Sorry for my ignorance, but I'm still not getting it.  The request handler is running on a thread, right?

    So if I offload the query to a pool thread, now I've got two threads in use, right? (Plus the cost of setting up the pool thread).  How is that a savings? 

    Admittedly when the query actually starts running, the onus shifts to the db itself, temporarily freeing up the pool thread. But  couldn't the original thread have done the same job?

    I do feel I'm missing something here but I'm just not sure what it is. 

    My thinking is that await-async is advantageous in situations where you're tempted to spin off 3 new threads (e.g. 3 db queries that should run simultaneously to minimize total execution time) . That's wasteful since existing pool-threads would be more efficient.  But in cases where I don't NEED to spin off any new threads (e.g. I only have one query to run), isn't it less expensive to just go ahead and use the current thread?


    • Edited by jal2 Monday, December 4, 2017 2:56 AM
    Monday, December 4, 2017 2:54 AM
  • Sorry for not making my point clear here.

    The thing that actually matter is "the threads in active state". When you're doing async call, the thread it is running on is temporarily put into sleep therefore not holding CPU resources.

    And yes, unless you do expect your query return lots of data that it'll need more than 1 second to return, you don't really gain performance benefit by doing it async way. (In my ex-company, it's only added for long queries and I don't bother convert code to async calls for everything)

    • Marked as answer by jal2 Monday, December 4, 2017 4:41 AM
    Monday, December 4, 2017 3:13 AM
    Answerer

  • I think I see my error now,  having read posts by Stephen Cleary and Eric Lippert
    https://stackoverflow.com/questions/39795286/does-async-await-increases-context-switching
    http://blog.stephencleary.com/2014/04/a-tour-of-task-part-0-overview.html
    I was assuming that .Net runs a Task by ThreadPool.QueueUserWorkerItem(Task) and thus it runs on a pool thread. To me this seemed (sometimes) beneficial because it unblocks the current thread, and avails of existing pool-threads instead of creating new ones.

    But apparently a (real) async task doesn't even use a pool thread, it doesn't use any thread at all. Rather it's essentially syntactic sugar for saying, "Let the db run  its query. Meanwhile the current thread can do something else."

    I use the word 'real' (real async task) because I've noticed, in my own experience, that await remains synchronous (the current thread is still being used for all its work) until a REAL async call is made such as dbContext.FindAsync(productId), only then is the current thread freed from awaited work. 

    So I'll assume that's what you were trying to tell me and  mark your posts as answer. 
    Monday, December 4, 2017 4:41 AM
  • Although oddly I seem to recall doing a  test in VS debugger and noticing a new threadId being created for an async call. That's part of why I assumed a Task was getting queued up to the thread pool.

    Maybe I'll  never get to the bottom of all this. 

    Monday, December 4, 2017 4:53 AM