使用线程池扩展 Web 客户端

发布于 12-13 03:26 字数 3203 浏览 1 评论 0原文

我必须使用 webclient 创建对同一 URL 的多个 Web 请求。我使用线程池 QueueUserWorkItem 生成线程。下面的代码显示了我如何生成线程并使用 WebClient 进行发布。我必须派生 Web 客户端类来设置 Expect100Continue 和 Timeout 属性。

当我在没有 Thread.Sleep(生成线程代码中的注释行)的情况下运行此代码时,我得到的响应时间超过 1500 毫秒。请检查PostToURL方法中计算响应时间的逻辑。但是如果我在生成另一个线程之前休眠 1 秒,我得到的响应时间将少于 300 毫秒。我找不到如此不同的原因。实际上我需要将响应时间提高到 300 毫秒。这是我为测试服务而编写的测试工具代码。您能指出为什么响应时间不同吗?

这是生成线程的代码

foreach (var nameValueCollection in requestCollections)
{
    NameValueCollection collection = nameValueCollection;
    ThreadPool.QueueUserWorkItem(a => { if (collection != null) PostToURL    
    (collection); });
    //Thread.Sleep(TimeSpan.FromSeconds(1));
 }

这是发布到 URL

public void PostToURL(NameValueCollection collection)
    {
        DateTime requestStartDate = DateTime.Now;
        DateTime requestEndDate = DateTime.Now;
        string encodedResponse;
        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);

                ServicePointManager.ServerCertificateValidationCallback =
                    new RemoteCertificateValidationCallback(delegate { return true; });

                requestStartDate = DateTime.Now;
                var responseArray = transportType2.UploadValues("http://xyz/Post.ashx?AccountName=myaccount",
                                                                "POST", collection);
                requestEndDate = DateTime.Now;
                Console.WriteLine(requestEndDate.Subtract(requestStartDate).TotalMilliseconds);

                encodedResponse = Encoding.ASCII.GetString(responseArray);

                transportType2.Dispose();
            }
        }
        catch (Exception exception)
        {
            requestEndDate = DateTime.Now;
            encodedResponse = exception.ToString();
        }

        //Global variable to record request and response
        responses.Add(new ServiceResponse
        {
            ResponseInMs = (int) requestEndDate.Subtract(requestStartDate).TotalMilliseconds,
            StartTime = requestStartDate,
            EndTime = requestEndDate,
            Response = encodedResponse,
            Request = string.Join(";", collection.Cast<string>()
                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
            ApplicationId = collection["ApplicationId"]

        });
    }

UPDATED 的方法 这是派生webclient的代码

public class DerivedWebClient: WebClient
{
    public bool Expect100Continue
    {
        get;
        set;
    }

    public TimeSpan Timeout
    {
        get;
        set;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = (HttpWebRequest)base.GetWebRequest(address);
        if (request != null)
        {
            request.ServicePoint.Expect100Continue = Expect100Continue;
            request.KeepAlive = false;
            request.Timeout = (int) Timeout.TotalMilliseconds;
        }

        return request;
    }
}

I have to create mutiple web request to same URL using webclient. I spawn thread using thread pool QueueUserWorkItem. Code below show how I am spawning thread and posting using WebClient. I had to derive web client class to set Expect100Continue and Timeout property.

When I run this code without Thread.Sleep (commented line in spawn thread code), I am getting response time over 1500 millisecond. Please check the logic to calculate response time in PostToURL method. But If I put 1 seconds sleep before spawning another thread, I am getting response time less than 300 milliseconds. I could not find reason why is that so different. Actually I need to bring this response time to 300 millisecond. This is test harness code that I am writing to test a service. Can you point why is different response time?

Here is the code that spawns the thread

foreach (var nameValueCollection in requestCollections)
{
    NameValueCollection collection = nameValueCollection;
    ThreadPool.QueueUserWorkItem(a => { if (collection != null) PostToURL    
    (collection); });
    //Thread.Sleep(TimeSpan.FromSeconds(1));
 }

Here is method that post to a URL

public void PostToURL(NameValueCollection collection)
    {
        DateTime requestStartDate = DateTime.Now;
        DateTime requestEndDate = DateTime.Now;
        string encodedResponse;
        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);

                ServicePointManager.ServerCertificateValidationCallback =
                    new RemoteCertificateValidationCallback(delegate { return true; });

                requestStartDate = DateTime.Now;
                var responseArray = transportType2.UploadValues("http://xyz/Post.ashx?AccountName=myaccount",
                                                                "POST", collection);
                requestEndDate = DateTime.Now;
                Console.WriteLine(requestEndDate.Subtract(requestStartDate).TotalMilliseconds);

                encodedResponse = Encoding.ASCII.GetString(responseArray);

                transportType2.Dispose();
            }
        }
        catch (Exception exception)
        {
            requestEndDate = DateTime.Now;
            encodedResponse = exception.ToString();
        }

        //Global variable to record request and response
        responses.Add(new ServiceResponse
        {
            ResponseInMs = (int) requestEndDate.Subtract(requestStartDate).TotalMilliseconds,
            StartTime = requestStartDate,
            EndTime = requestEndDate,
            Response = encodedResponse,
            Request = string.Join(";", collection.Cast<string>()
                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
            ApplicationId = collection["ApplicationId"]

        });
    }

UPDATED
Here is code that derive webclient

public class DerivedWebClient: WebClient
{
    public bool Expect100Continue
    {
        get;
        set;
    }

    public TimeSpan Timeout
    {
        get;
        set;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = (HttpWebRequest)base.GetWebRequest(address);
        if (request != null)
        {
            request.ServicePoint.Expect100Continue = Expect100Continue;
            request.KeepAlive = false;
            request.Timeout = (int) Timeout.TotalMilliseconds;
        }

        return request;
    }
}

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

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

发布评论

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

评论(2

方圜几里2024-12-20 03:26:50

默认情况下,.NET 的 HTTP 客户端会限制一定数量的并发连接。我怀疑您遇到了这个限制,因此每个线程在发出新请求之前都在等待空闲连接。

默认限制将根据您是否在 ASP.net 内运行客户端应用程序等而有所不同,但您可以更改它。使用 ServicePointManager.DefaultConnectionLimit 在全球范围内提高此限制。

.NET's HTTP client, by default, is throttled to a certain number of concurrent connections. I suspect you are running into this limit, so each thread is waiting for a free connection before making a new request.

The default limit is will vary depending on whether you're running a client app, inside ASP.net, etc. but you can change it. Use ServicePointManager.DefaultConnectionLimit to raise this limit globally.

笑红尘2024-12-20 03:26:50

此问题可能与UploadValuesAsync 响应时间重复。但代码块不同,我会考虑不同的问题,但问题是相同的。其他问题的答案也适用于此。

This question may be duplicate to UploadValuesAsync response time. But the code blocks are different I would consider different questions but the problem are same. Answer to the other question also, applies here.

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