4

I'm currently developing a small server application and getting to grips with Task<>, and other associated operations.

I'm wondering how Blocking operations work within a Task.

So for example, I currently use several Libraries with "blocking" operations. One of them is Npgsql (PostgreSQL provider.)

If I do the following...

Task myTask = new Task<>( () => 
    {
      using(var db = new PostgresqlDatabaseConnection())
      {
             db.ExecuteQuery("SELECT takes 50 ms to get data...")
             db.Insert(anObject); etc....
      }

   }
).Start();

And say, chain it to a bunch of other tasks that process that data.

Is this Efficient? I.E. Let's say that ExexuteQuery calls some kind of Thread.Sleep(1) or somehow blocks the thread, is this going to effect my Task Execution?

I'm asking because my server uses several libraries that would have to be rewritten to accomodate a totally Asynchronous methodology. Or is this Async enough?

*My Thoughts *

I'm really just not sure.

I know that if for example, the db.Executre() just ran a while(true) loop until it got it's data, it would almost certainly be blocking my server. Because a lot of time would be spend processing while(true). Or is Task smart enough to know that it should spend less time on this? Or if internally it is using some waiting mechanism, does the Task library know? Does it know that it should be processing some other task while it waits.

noseratio
  • 59,932
  • 34
  • 208
  • 486
user3431277
  • 43
  • 2
  • 4
  • When you say "chain it to a bunch of other tasks" do you mean you are doing `ContinueWith` to chain them together? If you are, than the second task will not execute until the first one completes. Rereading, I am guessing you mean `ContinueWith` since you say the subsequent tasks rely on that data. Further more, as far as efficiency goes, if task 2 requires the data from task 1 and task 3 requires task 2 than you really have to do them in sequence even if the first one sleeps. Don't think you can gain any efficiency there unless there are parts that are independent and can run parallel. – pstrjds Mar 18 '14 at 02:11
  • The general flow for my example: Recieve Request -> Get Database Data -> Do some Business Logic -> Send Back a request/or some other function. I'm more concerened about having 20 of these **get Datbase Data** tasks running at once and blocking execution of other server functions. ContinueWith would be used to chain the next task along, but this wouldn't be anywhere near the order of magnitude (in time) that getting database infomation is. – user3431277 Mar 18 '14 at 02:37

3 Answers3

4

I'm currently developing a small server application and getting to grips with Task<>, and other associated operations.

You won't benefit from using new Task, Task.Factory.StartNew, Task.Run in the server-side application, unless the number of concurrent client connections is really low. Check this and this for some more details.

You would however greatly benefit from using naturally asynchronous API. They don't block a pool thread while "in-flight", so the thread is returned to the pool and then can get busy serving another client request. This improves your server app scalability.

I'm not sure if PostgreSQL provides such API, look for something like ExecuteQueryAsync or BeginExecuteQuery/EndExecuteQuery. If it doesn't have that, just use the synchronous ExecuteQuery method, but do not offload it to a pool thread as you do in your code fragment.

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • @user3431277, apparently you've chosen to use `Task` wrappers to offload your synchronous code to a background thread in your server-side app. This is a well-known but still popular anti-pattern. Check this: http://blog.stephencleary.com/2013/10/taskrun-etiquette-and-proper-usage.html – noseratio Mar 20 '14 at 00:52
3

Using the async/await features of C# 5 will definitely make things easier. It can make asynchronous code easier to write, as you write it very similar to how you would write synchronous code.

Take the following example. I am using Thread.Sleep to simulate a long running operation, so any libraries that don't support async natively can still be used via Task.Run. While the Thread.Sleep is holding up the thread, your UI is still responsive. If you had written this code synchronously, your UI would hold up for 1.5 seconds until the thread.sleep was finished.

private async void button1_Click(object sender, EventArgs e)
{
    Console.WriteLine("0");
    await DoWorkAsync();
    Console.WriteLine("3");
}

private async Task DoWorkAsync()
{
    Console.WriteLine("1");
    await Task.Run(()=>
        {
            // Do your db work here.
            Thread.Sleep(1500);

        });
    Console.WriteLine("2");
}

So in short, if you have a long running database operations and you want to keep your UI responsive, you should leverage async/await. While this does keep your UI responsive, it does introduce new challenges like: what happens if the user clicks a button multiple times or what if the user closes the window while you are still processing to name some simple cases.

I encourage you to read further on the subject. Jon Skeet has a multi-part series on async. There are also numerous MSDN articles on the subject: 1 2 3 ...

John Koerner
  • 37,428
  • 8
  • 84
  • 134
1

Async programming does nothing to improve the efficiency of your logic or of the database. All it influences it the performance of switching between operations.

You cannot make a query or a computation faster wrapping it in a Task. You only add overhead.

Async IO is used on the server to achieve scalability to hundreds of concurrent requests. You don't need it here.

usr
  • 168,620
  • 35
  • 240
  • 369
  • In fact, it does! And I will move to them, however I have several other libs that don't. You answer has helped me solidify the concept in my mind. – user3431277 Mar 18 '14 at 22:39