我正在尝试将使用AsyncCallbacks的BeginXXX方法重写为使用async / await和XXXAsync方法的应用程序。但是我在性能方面遇到了一些麻烦。例如,这里是原始代码的片段,用于初始化一堆连接:
...
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);
}
}
我已将此重写为以下内容:
...
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;
}
}
TcpClients的初始化速度(连接,ssl握手和其他)的速度似乎存在巨大的性能差异。通过最初的方式,我可以在几秒钟内完成并初始化100个连接。在重写之后,可以花费30秒的时间来完成同样的事情。我可以在日志中看到各种回调函数是异步执行的,但一切都需要更长时间。我不确定我做错了什么?
另外我知道在这种情况下,围绕Async方法的try catch不会做任何事情,但现在不是问题。
举一个速度差异的例子,这是一个调试日志片段,当原始代码循环10次时:
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)
Async版本:
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)
答案 0 :(得分:0)
尝试以下操作,看看它是否与您的BeginXXX / EndXXX版本基准进行比较。
TcpClientState[] ConnectAll(string host, int port)
{
var states = new List<TcpClientState>();
for (int i = 1; i <= _maxTcpClients; i++)
{
TcpClientState tt = new TcpClientState(new TcpClient(), i);
Func<Task> connectAsync = async () =>
{
try
{
// note ConfigureAwait(false)
await tt.TcpClient.ConnectAsync(host, port).ConfigureAwait(false);
tt.SslStream = new SslStream(tt.TcpClient.GetStream(), false, Helper.ValidateServerCertificate, null);
await tt.SslStream.AuthenticateAsClientAsync(host);
// move here the code from SslAuthenticateCallback
// and so on ...
}
catch (Exception ex)
{
// you really want to do --_maxTcpClients ?
Interlocked.Decrement(ref _maxTcpClients);
Debug.Print(ex.ToString());
throw; // re-throw or handle
}
};
tt.ConnectionTask = connectAsync();
states.Add(tt);
}
return states.ToArray();
}