5

I have a Threading.Tasks.Task that handles a number of client socket operations (connecting, receiving and sending).

I understand that where possible it's best to use non blocking methods using Await because otherwise I'll end up with "parked threads waiting for their response". However, while the Socket class has async methods (SendAsync and so on) they aren't the same as the usual Task Parallel Library async methods, they don't return a Task and cannot be awaited.

I realise that I can wrap these socket async methods with a TaskCompletionSource but is there any benefit to doing so or will it ultimately still be parking the thread?

iguanaman
  • 930
  • 3
  • 13
  • 25

2 Answers2

15

As Servy explained. Using TaskCompletionSource as in of itself doesn't create (or park) any threads as long as you're using the asynchronous pattern correctly.

There are 3 different asynchronous patterns in the .Net framework:

  1. Asynchronous Programming Model (APM).
  2. Event-based Asynchronous Pattern (EAP).
  3. Task-based Asynchronous Pattern (TAP).

What you're trying to achieve is "convert" one pattern, the EAP, to another one, TAP. A simpler solution would be to use .Net's built-in "conversion" from the APM pattern to TAP, Task.Factory.FromAsync (which internally uses TaskCompletionSource):

APM

socket.BeginConnect(host, port, asyncResult =>
{
    socket.EndConnect(asyncResult);
    Console.WriteLine("Socket connected");
}, null);

TAP

await Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, host, port, null);
Console.WriteLine("Socket connected");
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • The `Socket` class uses an event based asynchronous model, and there is no general purpose `Task.FromEvent` method. ([Although you can try to write your own if you want.](http://stackoverflow.com/questions/12865848/general-purpose-fromevent-method)). – Servy Sep 12 '14 at 19:06
  • 1
    @Servy What do you mean? it has both event based methods and `BeginX`/`EndX` methods... – i3arnon Sep 12 '14 at 19:07
  • I'm trying to steer clear of the BeginXX/EndXX methods and use XXAsync instead. I am under the impression that the Begin/End have a larger memory overhead since they require a new IAsyncResult each time, whereas one SocketEventArgs (per socket) can be used by all methods (connect, send, receive) at the same time, as well as not needing to be recreated. I'm running a decent amount of sockets (1000 to 5000+), all active at the same time, so I'm trying to slim things down where possible. – iguanaman Sep 12 '14 at 19:32
  • 1
    @iguanaman I doubt that actually makes a difference. But that's for your consideration. – i3arnon Sep 12 '14 at 20:16
  • 2
    @iguanaman: The number of apps that actually need the `SocketEventArgs` API is incredibly small. You should use `FromAsync` unless you find you *need* to reduce garbage collections, in which case you can use [Toub's wrappers](http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx). But again, they are harder to use than `FromAsync` and completely overkill for 99.99% or more of apps. – Stephen Cleary Sep 12 '14 at 23:22
  • @StephenCleary Thank you. The reason I'm think it may be worth my while is the number of sockets concurrently connected (1000-5000+), which are all receiving data very often. Being in a busy IRC channel, for instance. Are you saying something like that wouldn't qualify for needing SocketEventArgs? – iguanaman Sep 13 '14 at 13:53
  • 2
    @iguanaman: I would say it doesn't qualify until you run a profiler proving it does. – Stephen Cleary Sep 13 '14 at 14:16
  • 1
    Here is a working link to [Stephen Toub's wrapper](https://devblogs.microsoft.com/pfxteam/awaiting-socket-operations) article. – PeterB Apr 12 '21 at 18:37
3

Translating a non-Task based asynchronous model to a task based asyncrhonous model through the use of a TaskCompletionSource does not create any new threads, no. It simply allows you to use a different syntax for interacting with that asynchronous operation.

It's not objectively better or worse, it's simply a different syntax for doing the same thing. Subjectively the task based model tend to be easier to use, but the whole design of both models means that they end up doing the same functional thing, assuming each is used properly.

Servy
  • 202,030
  • 26
  • 332
  • 449