I am trying to rewrite an application from using the BeginXXX methods with AsyncCallbacks to one that uses async/await and the XXXAsync methods. However I am having some trouble with performance. For example here is a snippet of the original code that's used to initialize a bunch of connections:
...
for (int i = 1; i <= _maxTcpClients; i++) {
TcpClientState tt = new TcpClientState(new TcpClient(), i);
try {
tt.TcpClient.BeginConnect(Host, Port, ConnectCallback, tt);
} catch (Exception ex) {
Log.Debug(
"Error on BeginConnect on RequestHandler (" + tt.HandlerId + ") request (" + tt.RequestId + ")",
ex);
CloseRequest(tt);
}
}
...
private static void ConnectCallback(IAsyncResult ar) {
TcpClientState tt = (TcpClientState)ar.AsyncState;
Log.Debug("ConnectCallback on TcpClient (" + tt.TcpClientId + ")");
try {
tt.TcpClient.EndConnect(ar);
} catch (Exception ex) {
Log.Debug("Error on EndConnect on TcpClient (" + tt.TcpClientId + ")", ex);
CloseRequest(tt);
Interlocked.Decrement(ref _maxTcpClients);
return;
}
tt.SslStream = new SslStream(tt.TcpClient.GetStream(), false, Helper.ValidateServerCertificate, null);
try {
tt.SslStream.BeginAuthenticateAsClient(Host, SslAuthenticateCallback, tt);
} catch (Exception ex) {
Log.Debug("Error on BeginAuthenticateAsClient on TcpClient (" + tt.TcpClientId + ")", ex);
CloseRequest(tt);
Interlocked.Decrement(ref _maxTcpClients);
}
}
I have rewritten this as the following:
...
for (int i = 1; i <= _maxTcpClients; i++) {
TcpClientState tt = new TcpClientState(new TcpClient(), i);
try {
tt.TcpClient.ConnectAsync(Host, Port).ContinueWith(t => ConnectCallback(tt));
} catch (Exception ex) {
Log.Debug("Error on ConnectAsync on TcpClient (" + tt.TcpClientId + ")", ex);
CloseRequest(tt);
Interlocked.Decrement(ref _maxTcpClients);
return;
}
}
...
private static void ConnectCallback(TcpClientState tt) {
Log.Debug("ConnectCallback on TcpClient (" + tt.TcpClientId + ")");
tt.SslStream = new SslStream(tt.TcpClient.GetStream(), false, Helper.ValidateServerCertificate, null);
try {
tt.SslStream.AuthenticateAsClientAsync(Host).ContinueWith(t => SslAuthenticateCallback(tt));
} catch (Exception ex) {
Log.Debug("Error on AuthenticateAsClientAsync on TcpClient (" + tt.TcpClientId + ")", ex);
CloseRequest(tt);
Interlocked.Decrement(ref _maxTcpClients);
return;
}
}
There appears to be an enormous performance difference in how quickly the TcpClients are initialized(connection, ssl handshake, and the rest). With the original way of doing it, I can loop through and initialize 100 connections in a few seconds. After rewriting it, it can take updwards of 30 seconds to accomplish the same thing. I can see in the logs that the various callback functions are being executed asynchronously, but everything just takes... longer. I am not sure what I am doing wrong?
Also I know the try catch around the Async methods won't do anything in this case, but that's not the issue right now.
To give an example of the speed difference, here is a debug log snippet when looping 10 times for the original code:
2014-02-25 22:37:06,076 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (1)
2014-02-25 22:37:06,076 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (3)
2014-02-25 22:37:06,077 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (6)
2014-02-25 22:37:06,077 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (10)
2014-02-25 22:37:06,077 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (7)
2014-02-25 22:37:06,077 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (4)
2014-02-25 22:37:06,077 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (8)
2014-02-25 22:37:06,078 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (9)
2014-02-25 22:37:06,079 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (5)
2014-02-25 22:37:06,082 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (2)
And the Async version:
2014-02-25 22:37:51,569 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (1)
2014-02-25 22:37:51,583 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (2)
2014-02-25 22:37:51,936 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (5)
2014-02-25 22:37:51,969 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (3)
2014-02-25 22:37:52,133 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (4)
2014-02-25 22:37:52,311 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (6)
2014-02-25 22:37:52,382 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (8)
2014-02-25 22:37:52,452 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (9)
2014-02-25 22:37:52,466 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (7)
2014-02-25 22:37:52,856 [] DEBUG CPT.Client (null) - ConnectCallback on TcpClient (10)
Try the following, see if it compares to your BeginXXX/EndXXX version benchmarks.