UploadValuesAsync响应时间

发布于 2024-12-13 16:33:40 字数 4053 浏览 0 评论 0原文

我正在编写测试工具来测试 HTTP Post。测试用例将在 Webclient 类中使用 UploadValuesAsync 以 10 秒的间隔发送 8 个 http 请求。每 8 个请求后它会休眠 10 秒。我正在记录每个请求的开始时间和结束时间。当我计算平均响应时间时。我得到了大约 800 毫秒。但是,当我在 Web 客户端中使用 UploadValues 方法同步运行此测试用例时,我得到的平均响应时间为 250 毫秒。你能告诉我为什么这两种方法有区别吗?我原以为 Aync 的响应时间会更短,但我没有得到这一点。

以下代码发送 8 个异步请求

                       var count = 0;
        foreach (var nameValueCollection in requestCollections)
        {
            count++;
            NameValueCollection collection = nameValueCollection;
            PostToURL(collection,uri);
            if (count % 8 == 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(10));
                count = 0;
            }
        }

UPDATED 这是发送 8 个请求 SYNC 的代码

public void PostToURLSync(NameValueCollection collection,Uri uri)
    {
        var response = new ServiceResponse
        {
            Response = "Not Started",
            Request = string.Join(";", collection.Cast<string>()
                                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
            ApplicationId = collection["ApplicationId"]

        };

        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);
                response.StartTime = DateTime.Now;
                var responeByte = transportType2.UploadValues(uri, "POST", collection);
                response.EndTime = DateTime.Now;
                response.Response = Encoding.Default.GetString(responeByte);
            }

        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
        response.ResponseInMs = (int)response.EndTime.Subtract(response.StartTime).TotalMilliseconds;
        responses.Add(response);
        Console.WriteLine(response.ResponseInMs);
    }

这是发布到 HTTP URI 的代码

public void PostToURL(NameValueCollection collection,Uri uri)
    {
        var response = new ServiceResponse
                        {
                            Response = "Not Started",
                            Request = string.Join(";", collection.Cast<string>()
                                                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
                            ApplicationId = collection["ApplicationId"]

                        };

        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);
                response.StartTime = DateTime.Now;
                transportType2.UploadValuesCompleted += new UploadValuesCompletedEventHandler(transportType2_UploadValuesCompleted);
                transportType2.UploadValuesAsync(uri, "POST", collection,response);
            }
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
    }

这是上传完成事件

    private void transportType2_UploadValuesCompleted(object sender, UploadValuesCompletedEventArgs e)
    {
        var now = DateTime.Now;
        var response = (ServiceResponse)e.UserState;
        response.EndTime = now;
        response.ResponseInMs = (int) response.EndTime.Subtract(response.StartTime).TotalMilliseconds;
        Console.WriteLine(response.ResponseInMs);

        if (e.Error != null)
        {
            response.Response = e.Error.ToString();
        }
        else
        if (e.Result != null && e.Result.Length > 0)
        {
            string downloadedData = Encoding.Default.GetString(e.Result);
            response.Response = downloadedData;
        }
        //Recording response in Global variable
        responses.Add(response);
    }

I am writing test harness to test a HTTP Post. Test case would send 8 http request using UploadValuesAsync in webclient class in 10 seconds interval. It sleeps 10 seconds after every 8 request. I am recording start time and end time of each request. When I compute the average response time. I am getting around 800 ms. But when I run this test case synchronously using UploadValues method in web client I am getting average response time 250 milliseconds. Can you tell me why is difference between these two methods? I was expecting the less response time in Aync but I did not get that.

Here is code that sends 8 requests async

                       var count = 0;
        foreach (var nameValueCollection in requestCollections)
        {
            count++;
            NameValueCollection collection = nameValueCollection;
            PostToURL(collection,uri);
            if (count % 8 == 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(10));
                count = 0;
            }
        }

UPDATED
Here is code that sends 8 requests SYNC

public void PostToURLSync(NameValueCollection collection,Uri uri)
    {
        var response = new ServiceResponse
        {
            Response = "Not Started",
            Request = string.Join(";", collection.Cast<string>()
                                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
            ApplicationId = collection["ApplicationId"]

        };

        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);
                response.StartTime = DateTime.Now;
                var responeByte = transportType2.UploadValues(uri, "POST", collection);
                response.EndTime = DateTime.Now;
                response.Response = Encoding.Default.GetString(responeByte);
            }

        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
        response.ResponseInMs = (int)response.EndTime.Subtract(response.StartTime).TotalMilliseconds;
        responses.Add(response);
        Console.WriteLine(response.ResponseInMs);
    }

Here is the code that post to the HTTP URI

public void PostToURL(NameValueCollection collection,Uri uri)
    {
        var response = new ServiceResponse
                        {
                            Response = "Not Started",
                            Request = string.Join(";", collection.Cast<string>()
                                                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
                            ApplicationId = collection["ApplicationId"]

                        };

        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);
                response.StartTime = DateTime.Now;
                transportType2.UploadValuesCompleted += new UploadValuesCompletedEventHandler(transportType2_UploadValuesCompleted);
                transportType2.UploadValuesAsync(uri, "POST", collection,response);
            }
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
    }

Here is the upload completed event

    private void transportType2_UploadValuesCompleted(object sender, UploadValuesCompletedEventArgs e)
    {
        var now = DateTime.Now;
        var response = (ServiceResponse)e.UserState;
        response.EndTime = now;
        response.ResponseInMs = (int) response.EndTime.Subtract(response.StartTime).TotalMilliseconds;
        Console.WriteLine(response.ResponseInMs);

        if (e.Error != null)
        {
            response.Response = e.Error.ToString();
        }
        else
        if (e.Result != null && e.Result.Length > 0)
        {
            string downloadedData = Encoding.Default.GetString(e.Result);
            response.Response = downloadedData;
        }
        //Recording response in Global variable
        responses.Add(response);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

野味少女 2024-12-20 16:33:40

您可能遇到的一个问题是,默认情况下,.NET 会将传出 HTTP 连接限制在相关 RFC 规定的限制(每个远程主机 2 个并发连接)。假设有 2 个并发连接,每个请求 250 毫秒,这意味着前 2 个请求的响应时间为 250 毫秒,第二个 2 个请求为 500 毫秒,第三个为 750 毫秒,最后一个为 1000 毫秒。这将产生 625 毫秒的平均响应时间,与您看到的 800 毫秒相差不远。

要消除限制,请增加 ServicePointManager.DefaultConnectionLimit< /code>到您想要支持的最大并发连接数,您应该会看到平均响应时间大幅下降。

第二个问题可能是服务器本身处理多个并发连接的速度比一次处理一个请求的速度慢。即使您解除了上述限制问题,我预计每个异步请求的平均执行速度也会比服务器一次仅执行一个请求的速度慢一些。慢多少取决于服务器针对并发请求的优化程度。

最后一个问题可能是由测试方法引起的。例如,如果您的测试客户端通过存储 cookie 并在每个请求中重新发送 cookie 来模拟浏览器会话,则某些服务器可能会序列化来自单个用户的请求,这可能会遇到问题。这通常是服务器应用程序的简化,因此它们不必处理锁定交叉请求状态(如会话状态)。如果您遇到此问题,请确保每个 WebClient 发送不同的 cookie 来模拟不同的用户。

我并不是说您会遇到所有这三个问题 - 您可能只会遇到 1 或 2 个 - 但这些是您所看到的问题最有可能的罪魁祸首。

One problem you're probably running into is that .NET, by default, will throttle outgoing HTTP connections to the limit (2 concurrent connections per remote host) that are mandated by the relevant RFC. Assuming 2 concurrent connections and 250ms per request, that means the response time for your first 2 requests will be 250ms, the second 2 will be 500ms, the third 750ms, and the last 1000ms. This would yield a 625ms average response time, which is not far from the 800ms you're seeing.

To remove the throttling, increase ServicePointManager.DefaultConnectionLimit to the maximum number of concurrent connections you want to support, and you should see your average response time go down alot.

A secondary problem may be that the server itself is slower handling multiple concurrent connections than handing one request at a time. Even once you unblock the throttling problem above, I'd expect each of the async requests to, on average, execute somewhat slower than if the server was only executing one request at a time. How much slower depends on how well the server is optimized for concurrent requests.

A final problem may be caused by test methodology. For example, if your test client is simulating a browser session by storing cookies and re-sending cookies with each request, that may run into problems with some servers that will serialize requests from a single user. This is often a simplification for server apps so they won't have to deal with locking cross-requests state like session state. If you're running into this problem, make sure that each WebClient sends different cookies to simulate different users.

I'm not saying that you're running into all three of these problems-- you might be only running into 1 or 2-- but these are the most likley culprits for the problem you're seeing.

一袭白衣梦中忆 2024-12-20 16:33:40

正如贾斯汀所说,我尝试了 ServicePointManager.DefaultConnectionLimit 但这并没有解决问题。我无法重现贾斯汀提出的其他问题。我首先不确定如何重现它们。

我所做的是,我在对等机器中运行了相同的代码,其响应时间完全符合我的预期。两台机器之间的区别在于操作系统。我的机器在 Windows Server 2003 上运行,其他机器在 Windows Server 2008 上运行。

由于它在其他机器上运行,我怀疑这可能是 Justin 指定的问题之一,也可能是 2003 上的服务器设置或其他问题。之后我并没有花太多时间来挖掘这个问题。由于这是一个测试工具,我们对此问题的优先级较低。我们没时间就离开了。

由于我不知道到底是什么解决了这个问题,所以我不接受除此之外的任何答案。因为至少我知道切换到 Server 2008 解决了这个问题。

As Justin said, I tried ServicePointManager.DefaultConnectionLimit but that did not fix the issue. I could not able reproduce other problems suggested by Justin. I am not sure how to reproduce them in first place.

What I did, I ran the same piece of code in peer machine that runs perfectly response time that I expected. The difference between the two machines is operating systems. Mine is running on Windows Server 2003 and other machine is running on Windows Server 2008.

As it worked on the other machines, I suspect that it might be one of the problem specified by Justin or could be server settings on 2003 or something else. I did not spend much time after that to dig this issue. As this is a test harness that we had low priority on this issue. We left off with no time further.

As I have no glue on what exactly fixed it, I am not accepting any answer other than this. Becuase at very least I know that switching to server 2008 fixed this issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文