【问题标题】:.NET HTTPClient Asynchronous Limitations.NET HTTPClient 异步限制
【发布时间】:2013-08-08 07:30:32
【问题描述】:

我有一个小型 .Net 4.5 C# 应用程序,它从数据源读取信息,然后将此信息推送到一个网站,该网站是一个带有简单控制器的 .NET 4.5 Web API 网站。控制器接收数据并将其放入数据库。

以下对我有用,只要应用程序可以读取它可以写入并且所有内容最终都在数据库中:

    public static void PostDataToWebApi(MyDataClass tData)
    {
        HttpResponseMessage s = null;

        try
        {
            s = client.PostAsJsonAsync("/api/Station/Collector", tData).Result;
            s.EnsureSuccessStatusCode();
        }
        catch (Exception e)
        {
            Console.WriteLine("ERROR (ClientPost): " + e.ToString());
        }
    }

以下不起作用。它发布了大约一千多条记录,然后出现了一些错误,所有错误都带有“任务已取消”的消息,但大约 10 秒后它恢复处理:

    public static async void PostDataToWebApi(MyDataClass tData)
    {
        HttpResponseMessage s = null;

        try
        {
            s = await client.PostAsJsonAsync("/api/Station/Collector", tData);
            s.EnsureSuccessStatusCode();
        }
        catch (Exception e)
        {
            Console.WriteLine("ERROR (ClientPost): " + e.ToString());
        }
    }

完整的错误是:

    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
    at IICE_DataCollector_Remote.Program.<PostDataToWebApi>d__7.MoveNext() in e:\Users\TestUser.TEST\Documents\Visual Studio 2012\Projects\Test_App-trunk\TestCollector\Program.cs:line 475

对此有什么快速解决方法吗?据我所知,它用完了一些东西,线程,套接字,谁知道:-)

任何指针都将不胜感激,我很乐意让它工作,因为您可以想象同步执行 POST 比异步执行要慢得多。

只是为了确保它不是我的机器、本地防病毒软件或网络,我在 W2k8 R2 服务器、Windows 7 虚拟访客桌面(新版本)和 Windows 8 机器上尝试过相同的结果。

更多信息:我已经通过具有较小数据集(10,000 条记录)和 DefaultConnectionLimit 100 的 LAN 连接进行了部分成功测试。但是,在发布时有 500,000 条记录的生产通过 Internet 到远程服务器(仍然低延迟 25ms-50ms)我没有任何成功。

提前感谢您的帮助:-)

【问题讨论】:

  • 这个异常有什么信息?
  • 您的第二个版本中没有缺少await 吗?看起来它甚至不应该编译......
  • @JonSkeet 你是对的,代表我复制和粘贴错误!已更正此问题。
  • @CuongLe 消息是“任务被取消”
  • @Dominik:默认为 2,这是一个非常好的公共服务器访问设置。由于这是您的服务器,因此您可以将其设置为您认为可以接受的任何值(最好留一些喘息的空间,并记住 SQL Server 通常不会像 WebAPI 那样扩展)。试验并找到合适的设置后,您可以在客户端使用 SemaphoreSlim 来限制您的请求。

标签: c# .net async-await dotnet-httpclient


【解决方案1】:

好的,我现在可以使用它了。最重要的是为服务器微调客户端的设置。根据我是在本地运行测试还是通过 Internet 运行测试,这些设置会有所不同。

我的“PostDataToWebApi”方法现在看起来像这样:

    public static async void PostDataToWebApi(MyDataClass tData)
        {

        await throttler.WaitAsync();
        allTasks.Add(Task.Run(async () =>
        {

            try
            {
                var s = await client.PostAsJsonAsync("/api/Station/Collector", tData).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR (ClientPost): " + e.ToString());
            }
            finally
            {
                throttler.Release();
            }
        }));
    }

我在控制台应用程序的顶部声明了以下内容:

    private static List<Task> allTasks = new List<Task>();
    private static SemaphoreSlim throttler;

在我的循环开始之前,我有以下内容,更改了变量以确保一切正常:

    ServicePointManager.DefaultConnectionLimit = _DefaultConnections;
    ServicePointManager.MaxServicePointIdleTime = _MaxIdleTime;
    ServicePointManager.Expect100Continue = false;
    ServicePointManager.CheckCertificateRevocationList = false;

    throttle = new SemaphoreSlim(initialCount: _MaxQueue);

作为指导,对于基于 Internet 的交易,以下内容对我有用:

  1. 默认连接数:24
  2. 最大空闲时间:400
  3. SemaphoreSlim 初始计数:50

对于我的 LAN 测试,我可以同时运行默认连接和更高的初始计数值而不会出现问题,我猜这是可以预料的 :-)

最后,在我看来,我有以下内容以确保我不会杀死任何在执行运行结束时仍在运行的任务:

     await Task.WhenAll(allTasks);

希望这会有所帮助!

【讨论】:

  • 感谢您的自我回答!这似乎违反直觉,但我发现根据示例设置让信号量初始计数高于连接计数很重要。否则吞吐量会大大降低。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-03
  • 1970-01-01
相关资源
最近更新 更多