Make an Async/Await db call within a Task?

2019-05-26 22:16发布

问题:

We have a WCF service that is processing incoming messages in the following manner:

public bool ProcessMessage(string message)
{
    var returnValue = GetReturnValue();

    Task.Run(() => {
        //do some things with the message
        UpdateDatabase();
        SendRepliesOverNetwork();
    });

    return returnValue;
}

In an effort to process as many messages as possible, we added the task here. We want to return the returnValue to the caller as quickly as possible and let the Task do its thing.

My question: is there is any advantage to using the awaitable async database calls and/or using async methods for the replies over the network?

I'm cautious, as I think this may create too much context switching. We're already seeing the app using 100+ threads under load.

回答1:

First, I suggest you take a step back and really ask if returning early is a good idea. What you're doing is usually dangerous; you're returning the "OK" to the client before doing the actual processing. This is only a good idea if your client knows that "returnValue" doesn't mean the action is complete and only considers it complete upon receiving the "SendReplies".

That said, yes, you should see some benefit from making everything asynchronous that you can. If all your tasks are nonblocking, you'll get better use out of your thread pool (less context switching).

public bool ProcessMessage(string message)
{
  var returnValue = GetReturnValue();

  Task.Run(async () => {
    //do some things with the message
    await UpdateDatabaseAsync();
    await SendRepliesOverNetworkAsync();
  });

  return returnValue;
}


回答2:

I can see a couple of potential problems with this approach.

Firstly, if you're hosting your WCF service in IIS, using background threads that live longer than the request is a big no-no. When a request is complete, IIS is at liberty to tear down the whole AppDomain which will abort all background work with extreme predjudice!

Secondly, WCF will throttle requests if existing work is mounting up. With this pattern, you are handling the requests quickly and the amount of work queued for the thread pool may increase without limit.


You could try using WCF asynchronous service methods. This would free up threads that are just waiting for IO - your database and network access - which can improve throughput.

There's an in-depth article about this approach here: Dan Rigsby: Async Operations in WCF

Also, there's a section in MSDN here: WCF: Synchronous and Asynchronous Operations