本文介绍了从使用的BeginXXX到XXXAsync重写插座和流code的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想重写一个应用程序使用的BeginXXX方法与AsyncCallbacks到使用异步/等待和XXXAsync方法。不过我有一些性能的麻烦。例如,下面是这是我们用来初始化一串连接的原始code的一个片段:

  ...
    的for(int i = 1; I< = _maxTcpClients;我++){
        TcpClientState TT =新TcpClientState(新的TcpClient(),I);
        尝试 {
            tt.TcpClient.BeginConnect(主机,端口,ConnectCallback,TT);
        }赶上(例外前){
            Log.Debug(
                上RequestHandler的上BeginConnect误差(+ tt.HandlerId +)请求(+ tt.RequestId +),
                前);
            CloseRequest(TT);
        }
    }
...
    私有静态无效ConnectCallback(IAsyncResult的AR){
        TcpClientState TT =(TcpClientState)ar.AsyncState;
        Log.Debug(ConnectCallback上的TcpClient(+ tt.TcpClientId +));

        尝试 {
            tt.TcpClient.EndConnect(AR);
        }赶上(例外前){
            Log.Debug(+ tt.TcpClientId +),关于的TcpClient(上EndConnect错误,前);
            CloseRequest(TT);
            Interlocked.Decrement(REF _maxTcpClients);
            返回;
        }

        tt.SslStream =新的SslStream(tt.TcpClient.GetStream(),假的,Helper.ValidateServerCertificate,NULL);
        尝试 {
            tt.SslStream.BeginAuthenticateAsClient(主机,SslAuthenticateCallback,TT);
        }赶上(例外前){
            Log.Debug(+ tt.TcpClientId +),关于的TcpClient(上BeginAuthenticateAsClient错误,前);
            CloseRequest(TT);
            Interlocked.Decrement(REF _maxTcpClients);
        }
    }
 

我已经重写这个如下:

  ...
    的for(int i = 1; I< = _maxTcpClients;我++){
            TcpClientState TT =新TcpClientState(新的TcpClient(),I);
            尝试 {
                tt.TcpClient.ConnectAsync(主机,端口).ContinueWith(T => ConnectCallback(TT));
            }赶上(例外前){
                Log.Debug(上的TcpClient上ConnectAsync错误(+ tt.TcpClientId +),前);
                CloseRequest(TT);
                Interlocked.Decrement(REF _maxTcpClients);
                返回;
            }
        }
...
    私有静态无效ConnectCallback(TcpClientState TT){
        Log.Debug(ConnectCallback上的TcpClient(+ tt.TcpClientId +));

        tt.SslStream =新的SslStream(tt.TcpClient.GetStream(),假的,Helper.ValidateServerCertificate,NULL);
        尝试 {
            tt.SslStream.AuthenticateAsClientAsync(主机).ContinueWith(T => SslAuthenticateCallback(TT));
        }赶上(例外前){
            Log.Debug(上的TcpClient上AuthenticateAsClientAsync错误(+ tt.TcpClientId +),前);
            CloseRequest(TT);
            Interlocked.Decrement(REF _maxTcpClients);
            返回;
        }
    }
 

似乎有在有多快TcpClients被初始化一个巨大的性能差异(连接,SSL握手,其余)。随着做它的原始的方式,我可以遍历并初始化在几秒钟100个连接。改写后,可能需要30秒updwards来完成同样的事情。我可以在不同的回调函数被异步执行的日志中看到的,但一切都只是需要...更长的时间。我不知道我在做什么错了?

此外,我知道周围的异步方法不会做在这种情况下,任何的尝试捕捉,但是这不是问题现在。

要给出速度差的一个例子,这里是循环10次,原来的code当一个调试日志片断:

  2014年2月25日22:37:06076 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(1)
2014年2月25日22:37:06076 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(3)
2014年2月25日22:37:06077 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(6)
2014年2月25日22:37:06077 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(10)
2014年2月25日22:37:06077 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(7)
2014年2月25日22:37:06077 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(4)
2014年2月25日22:37:06077 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(8)
2014年2月25日22:37:06078 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(9)
2014年2月25日22:37:06079 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(5)
2014年2月25日22:37:06082 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(2)
 

和异步版本:

  2014年2月25日22:37:51569 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(1)
2014年2月25日22:37:51583 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(2)
2014年2月25日22:37:51936 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(5)
2014年2月25日22:37:51969 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(3)
2014年2月25日22:37:52133 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(4)
2014年2月25日22:37:52311 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(6)
2014年2月25日22:37:52382 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(8)
2014年2月25日22:37:52452 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(9)
2014年2月25日22:37:52466 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(7)
2014年2月25日22:37:52856 [] DEBUG CPT.Client(空) -  ConnectCallback上的TcpClient(10)
 

解决方案

请尝试以下,看它是否比作你的BeginXXX / EndXXX版本基准。

  TcpClientState [] ConnectAll(字符串主机,INT端口)
{
    VAR状态=新的名单,其中,TcpClientState>();

    的for(int i = 1; I< = _maxTcpClients;我++)
    {
        TcpClientState TT =新TcpClientState(新的TcpClient(),I);

        FUNC<任务> connectAsync =异步()=>
        {
            尝试
            {
                //注意ConfigureAwait(假)
                等待tt.TcpClient.ConnectAsync(主机,端口).ConfigureAwait(假);
                tt.SslStream =新的SslStream(tt.TcpClient.GetStream(),假的,Helper.ValidateServerCertificate,NULL);
                等待tt.SslStream.AuthenticateAsClientAsync(主机);

                //这里移动从SslAuthenticateCallback的code
                // 等等 ...
            }
            赶上(例外前)
            {
                //你真正想做的事情--_ maxTcpClients?
                Interlocked.Decrement(REF _maxTcpClients);

                Debug.Print(ex.ToString());
                扔; //重新抛出或处理
            }
        };

        tt.ConnectionTask = connectAsync();
        states.Add(TT);
    }

    返回states.ToArray();
}
 

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.

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

这篇关于从使用的BeginXXX到XXXAsync重写插座和流code的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-24 06:12