0

I found that for expensive IO bound operation I can use TaskCompletionSource

as shown here http://msdn.microsoft.com/en-us/library/hh873177.aspx#workloads

But the example shown is only waiting for some time and return DateTime.

public static Task<DateTimeOffset> Delay(int millisecondsTimeout)
{
 TaskCompletionSource<DateTimeOffset> tcs = null;
 Timer timer = null;

 timer = new Timer(delegate
 {
    timer.Dispose();
    tcs.TrySetResult(DateTimeOffset.UtcNow);
 }, null, Timeout.Infinite, Timeout.Infinite);

 tcs = new TaskCompletionSource<DateTimeOffset>(timer);
 timer.Change(millisecondsTimeout, Timeout.Infinite);
 return tcs.Task;
}

Above code waits for timeout. I have a database call which I want to fire in the above way, but little confused in how to write it:

   using (var context = new srdb_sr2_context())
   {
      return context.GetData("100", "a2acfid");
   }

I wrote the function as below, but not sure if this is correct way of doing it:

TaskCompletionSource<IList<InstructorsOut>> tcs = null;
        Timer timer = null;

        timer = new Timer(delegate
        {
            timer.Dispose();

            //prepare for expensive data call
            using (var context = new srdb_sr2_context())
            {
                var output = context.GetData("100", "a2acfid");

                //set the result
                tcs.TrySetResult(output);
            }  

        }, null, Timeout.Infinite, Timeout.Infinite);

        tcs = new TaskCompletionSource<IList<InstructorsOut>>(timer);
        timer.Change(0, Timeout.Infinite);
        return tcs.Task;

Any help would be appreciated.

Sanjay Sutar
  • 544
  • 1
  • 5
  • 18
  • The reason for the confusion is that TaskCompletionSource is NOT about running IO bound operations. It's about providing a Task-based wrapper over other asynchronous operations, eg. timer delays, events, callbakcs. Besides, database operations are NOT IO bound operations. They actually have very little IO while they wait for results – Panagiotis Kanavos Aug 20 '13 at 13:58

1 Answers1

1

Your code doesn't make much sense to me. Timer is useful if you want to execute the code after some time, but that's not what you need here.

If you want to execute an operation on a background thread, you can use Task.Run():

Task<IList<InstructorsOut>> GetDataBackground()
{
    return Task.Run(() =>
    {
        using (var context = new srdb_sr2_context())
        {
            return context.GetData("100", "a2acfid");
        }  
    });
}

Using a background thread this way can be useful in UI apps, where you don't want to block the UI thread. But if you have something like ASP.NET application, this won't actually give you any performance or scalability improvements. For that, the GetData() method would have to be made truly asynchronous.

svick
  • 236,525
  • 50
  • 385
  • 514
  • That's exactly my question is: How to make GetData() truly asynchronous. I have also added the MSDN link which shows using Timer to do it. – Sanjay Sutar Aug 05 '13 at 14:30
  • Well, you can't (assuming you can't directly modify `GetData()`). The author of the library that contains `GetData()` has to do that. – svick Aug 05 '13 at 14:38
  • GetData() is entity framework Function Import. So I can't really do anything there since EF 5.0 does not support async operations. – Sanjay Sutar Aug 05 '13 at 19:31
  • 1
    @SanjaySutar In that case, there's nothing you can do (except for switching to EF 6.0). – svick Aug 05 '13 at 19:39