Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task vs AsParallel()

Tags:

c#

task

plinq

On page 33 of Stephen Toub's book

http://www.microsoft.com/download/en/details.aspx?id=19222

There is the code

var pings = from addr in addrs.AsParallel().WithDegreeOfParallelism(16)
   select new Ping().Send(addr);
foreach (var ping in pings)
   Console.WriteLine("{0}: {1}", ping.Status, ping.Address);

and according to Stephen the better version

var pings = (from addr in addrs
    select new Ping().SendTask(addr, null)).ToArray();
Task.WaitAll(pings);
foreach (Task<PingReply> ping in pings)
    Console.WriteLine("{0}: {1}", ping.Result.Status, ping.Result.Address);

Stephen says the 2nd option is better because "Task abstraction can also be used to represent I/O-bound operations and without tying up a thread in the process."

But doesn't a Task just use the Threadpool(hence just using threads anyway) underneath anyway? So you are in fact tying up a thread?

like image 552
TheWommies Avatar asked Jan 20 '12 11:01

TheWommies


1 Answers

Not all tasks represent work to be done on a thread. Just about any task returned from TaskCompletionSource represents something "other". And if we delve into the SendTask method, we find it calls SentTaskCore:

private static Task<PingReply> SendTaskCore(Ping ping, object userToken, Action<TaskCompletionSource<PingReply>> sendAsync)
    {
        // Validate we're being used with a real smtpClient.  The rest of the arg validation
        // will happen in the call to sendAsync.
        if (ping == null) throw new ArgumentNullException("ping");

        // Create a TaskCompletionSource to represent the operation
        var tcs = new TaskCompletionSource<PingReply>(userToken);

        // Register a handler that will transfer completion results to the TCS Task
        PingCompletedEventHandler handler = null;
        handler = (sender, e) => EAPCommon.HandleCompletion(tcs, e, () => e.Reply, () => ping.PingCompleted -= handler);
        ping.PingCompleted += handler;

        // Try to start the async operation.  If starting it fails (due to parameter validation)
        // unregister the handler before allowing the exception to propagate.
        try
        {
            sendAsync(tcs);
        }
        catch(Exception exc)
        {
            ping.PingCompleted -= handler;
            tcs.TrySetException(exc);
        }

        // Return the task to represent the asynchronous operation
        return tcs.Task;
    }

So, no, it's not blocking a thread - it's using the async completion mechanisms to avoid tying up a thread.


From the docs on TaskCompletionSource:

Represents the producer side of a Task unbound to a delegate, providing access to the consumer side through the Task property.

So, as it says, it supports a Task that isn't bound to a delegate - it allows you to hand someone a Task, and then orchestrate how that task gets completed, when completion involves something other than executing a delegate.

like image 87
Damien_The_Unbeliever Avatar answered Sep 20 '22 02:09

Damien_The_Unbeliever