C# 将套接字和流代码从使用BeginXXX重写为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

我正在尝试将一个应用程序从使用带有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);
        }
    }
和异步版本:

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();
}