C# 同步并发HttpClient使用

C# 同步并发HttpClient使用,c#,asynchronous,concurrency,c#-5.0,dotnet-httpclient,C#,Asynchronous,Concurrency,C# 5.0,Dotnet Httpclient,我试图同步使用HttpClient,但当我发出许多并发请求时,它就会停止工作。我编写了两个测试,一个用于异步使用,另一个用于同步使用测试方法始终在4秒后返回响应。异步测试工作正常。在同步测试中,几乎所有请求都超时,最后只有约20个请求成功。我尝试对请求使用单个HttpClient,并为每个新请求创建新的HttpClient实例。没有区别。也许这跟我有关 我将VS2013与.NET Framework 4.5.1一起使用,目标是Framework 4.5。我通过NuGet获取HttpClient:

我试图同步使用HttpClient,但当我发出许多并发请求时,它就会停止工作。我编写了两个测试,一个用于异步使用,另一个用于同步使用<代码>测试方法始终在4秒后返回响应。异步测试工作正常。在同步测试中,几乎所有请求都超时,最后只有约20个请求成功。我尝试对请求使用单个
HttpClient
,并为每个新请求创建新的
HttpClient
实例。没有区别。也许这跟我有关

我将VS2013与.NET Framework 4.5.1一起使用,目标是Framework 4.5。我通过NuGet获取HttpClient:

我现在还不想异步使用
HttpClient
,因为这意味着我必须重写整个应用程序。你知道我做错了什么吗

// all 800 requests complete successfully
[Test]
public async void Asyncmethod()
{
    var sw = new Stopwatch();
    sw.Start();

    var client = new HttpClient();
    client.Timeout = TimeSpan.FromSeconds(15);

    var tasks = Enumerable.Range(0, 800).Select(x => Task.Run(async () =>
    {
        try
        {
            var swx = new Stopwatch();
            swx.Start();
            var response = await client.GetStringAsync("http://localhost:7002/TestMethod").ConfigureAwait(false);
            swx.Stop();
            Console.WriteLine(x + " " + response + " in " + swx.ElapsedMilliseconds + " ms.");
        }
        catch (Exception e)
        {
            Console.WriteLine(x + " Exception: " + e.Message);
        }
    })).ToArray();

    await Task.WhenAll(tasks);

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

// almost all of 800 requests time out
[Test]
public void Syncmethod()
{
    var sw = new Stopwatch();
    sw.Start();

    var client = new HttpClient();

    var tasks = Enumerable.Range(0, 800).Select(x => Task.Run(() =>
    {
        try
        {
            var swx = new Stopwatch();
            swx.Start();
            var response = client.GetStringAsync("http://localhost:7002/TestMethod");
            if (response.Wait(15000))
            {
                swx.Stop();
                Console.WriteLine(x + " " + response.Result + " in " + swx.ElapsedMilliseconds + " ms.");
            }
            else
            {
                swx.Stop();
                Console.WriteLine(x + " timed out.");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(x + " Exception: " + e.Message);
        }
    })).ToArray();

    foreach (var task in tasks)
        task.Wait(60000);

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

是的,好像是僵局

这个代码工作得很完美

public static void Syncmethod()
    {
        var sw = new Stopwatch();
        sw.Start();

        var client = new HttpClient();

        var tasks = Enumerable.Range(0, 800).Select(x => Task.Run(() =>
        {

            var swx = new Stopwatch();
            swx.Start();
            var result =
            client.GetStringAsync("http://yandex.ru").ContinueWith(task =>
            {
                try
                {
                    swx.Stop();
                    Console.WriteLine(x + " " + task.Result + " in " + swx.ElapsedMilliseconds + " ms.");
                    return task.Result;
                }
                catch (Exception e)
                {
                    swx.Stop();
                    Console.WriteLine(x + " Exception: " + e.Message);
                    throw e;
                }
            }, TaskContinuationOptions.AttachedToParent);

        })).ToArray();

        foreach (var task in tasks)
            task.Wait(60000);

        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
我想您需要额外的逻辑来处理超时。例如,可能还有一个任务在15秒内完成

看看这篇文章

如上所述,您可以通过简单的更改挂起异步示例

var response = client.GetStringAsync("http://yandex.ru").GetAwaiter().GetResult();

在编写异步代码时,永远不要使用阻止执行并等待结果。

我建议您对
HttpClient
使用
Wait
,而不要使用
Wait
。如果您真的想要同步请求,请考虑使用支持同步方法的<代码> WebClient < /代码>。
也就是说,我相信您看到这种行为的原因是由于
ServicePointManager.DefaultConnectionLimit
,它将限制对给定服务器的请求数量。如果您希望对同一服务器有大量并发请求(同步或异步),则需要增加该限制(UI应用程序默认为2)。

等待
-在所有问题都标记为C#-5.0之后,问题是,如果没有超时,则所有请求都不会完成。只有在780个请求由于超时而被取消后,我才收到大约20个已完成的请求。在not选项中使用WAIT,我还必须重写其他所有请求。是的,
WebClient
工作正常。但是我仍然不明白为什么
HttpClient
挂起。
DefaultConnectionLimit
是挂起的一个很好的理由。默认值为2,这意味着即使获得20个已完成的请求也不错。首先,在您的示例中,如果请求足够长,任务将在请求完成之前完成。其次,如何编写一个函数,使用
ContinueWith
?Updated从响应中返回一些内容。但您必须重写代码,以便在不等待的情况下使用Task。