C# 将套接字和流代码从使用BeginXXX重写为XXXAsync
我正在尝试将一个应用程序从使用带有AsyncCallbacks的BeginXXX方法重写为使用async/await和XXXAsync方法的应用程序。但是,我在性能方面遇到了一些问题。例如,以下是用于初始化一组连接的原始代码片段:C# 将套接字和流代码从使用BeginXXX重写为XXXAsync,c#,.net,sockets,asynchronous,C#,.net,Sockets,Asynchronous,我正在尝试将一个应用程序从使用带有AsyncCallbacks的BeginXXX方法重写为使用async/await和XXXAsync方法的应用程序。但是,我在性能方面遇到了一些问题。例如,以下是用于初始化一组连接的原始代码片段: ... for (int i = 1; i <= _maxTcpClients; i++) { TcpClientState tt = new TcpClientState(new TcpClient(), i); try
...
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);
}
}
和异步版本:
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)
尝试以下方法,看看它是否与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();
}
TcpClientState[]ConnectAll(字符串主机,int端口)
{
var states=新列表();
对于(int i=1;i
{
尝试
{
//注意配置等待(错误)
wait tt.TcpClient.ConnectAsync(主机、端口).configurewait(false);
tt.SslStream=新的SslStream(tt.TcpClient.GetStream(),false,Helper.ValidateServerCertificate,null);
等待tt.SslStream.AuthenticateTasClientAsync(主机);
//将SslAuthenticateCallback中的代码移到这里
//等等。。。
}
捕获(例外情况除外)
{
//你真的想做--\u maxTcpClients?
联锁减量(参考maxTcpClients);
Print(例如ToString());
抛出;//重新抛出或处理
}
};
tt.ConnectionTask=connectAsync();
添加(tt);
}
返回状态。ToArray();
}
为什么ContinueWith
而不是async/await
,您是否仅限于VS2010?如果您需要以.NET 4.0为目标,但有一个使用VS2012+开发的选项,您可以使用并且仍然有async/await
。如果您坚持使用ContinueWith
,请尝试ExecuteSynchronously
,例如:ConnectAsync(主机、端口).ContinueWith(t=>ConnectCallback(tt),TaskContinuationOptions.ExecuteSynchronously)
。不,我使用的是VS2012,目标是.NET 4.5。我不能使用await,因为这是一个for循环。你仍然可以使用await
,我将演示如何使用。它的执行环境是什么:WinForms/WPF应用程序、控制台、服务、ASP.NET等?非常感谢,环境是WinFormsun幸运的是没有帮助,仍然得到缓慢的结果ts.@RadAway,这很奇怪。我相信Async
套接字API只是围绕BeginXXX/EndXXX API的包装。您可以尝试对任务执行相同的操作。fromsync
,比如。然后它真的应该执行与BeginXXX/EndXXX
相同的操作。不幸的是,这没有多大帮助,仍然得到缓慢的结果。我举了您的例子,并将for循环中的代码敲入匿名异步函数。我在该函数中做的唯一一件事是“wait tt.TcpClient.ConnectAsync(主机、端口).configurewait(false);”正如您所建议的,下一行只是在日志中写入一个条目。循环10次只花了不到1秒的时间,而原始的循环只花了16毫秒。@RadAway,我可能会责怪DNS解析可能在ConnectAsync
内部同步进行。但这并不能解释为什么Task.fromsync
在rom Begin/EndXXX。为了更进一步,您需要在系统外创建一些可复制的东西。我认为问题在于键盘和椅子之间的某个地方……在app.config中,我已为此版本的代码启用了system.diagnostics套接字跟踪。禁用它当然会修复性能。感谢您的所有帮助它为我提供了一些新的知识。
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)
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();
}