首页 > 解决方案 > 长 API 调用 - 异步调用答案?

问题描述

我正在调用一个很慢的外部 API。目前,如果我暂时没有调用 API 来获取一些订单,则可以将调用分解为页面(分页)。

因此,获取订单可能会进行多次调用,而不是 1 次调用。有时每次通话可能需要大约 10 秒,因此总共可能需要大约一分钟,这太长了。

        GetOrdersCall getOrders = new GetOrdersCall();
        getOrders.DetailLevelList.Add(DetailLevelCodeType.ReturnSummary);
        getOrders.CreateTimeFrom = lastOrderDate;
        getOrders.CreateTimeTo = DateTime.Now;

        PaginationType paging = new PaginationType();
        paging.EntriesPerPage = 20;
        paging.PageNumber = 1;

        getOrders.Pagination = paging;

        getOrders.Execute();

        var response = getOrders.ApiResponse;
        OrderTypeCollection orders = new OrderTypeCollection();

        while (response != null && response.OrderArray.Count > 0)
        {
            eBayConverter.ConvertOrders(response.OrderArray, 1);

            if (response.HasMoreOrders)
            {
                getOrders.Pagination.PageNumber++;
                getOrders.Execute();

                response = getOrders.ApiResponse;
                orders.AddRange(response.OrderArray);
            }
        }

这是我上面代码的摘要...... getOrders.Execute() 是api触发的时候。

在第一个“getOrders.Execute()”之后有一个分页结果,它告诉我有多少页数据。我的想法是我应该能够为每个页面启动异步调用并填充 OrderTypeCollection。当所有调用都完成并且集合完全加载时,我将提交到数据库。

我以前从未通过 c# 进行过异步调用,我可以遵循 Async await 但我认为我的场景超出了我迄今为止所做的阅读范围?

问题:

  1. 我想我可以将它设置为异步触发多个调用,但我不确定如何检查所有任务何时完成,即准备好提交到数据库。
  2. 我在某处读过我想避免将 API 调用和 db 写入结合起来以避免锁定 SQL Server - 这是正确的吗?

如果有人能指出我正确的方向 - 将不胜感激。

标签: c#async-await

解决方案


我想我可以将它设置为异步触发多个调用,但我不确定如何检查所有任务何时完成,即准备好提交到数据库。

是的,你可以打破这个

问题是ebay没有async Task Execute方法,所以你只剩下阻塞线程调用并且没有IO 优化的异步等待模式。如果有的话,你可以利用一个TPL Dataflow管道,它是有async意识的(并且全家人都可以玩),无论如何你都可以,尽管我提出了一个普通的TPL解决方案......

然而,一切都没有失去,只是回落到Parallel.For和一个ConcurrentBag<OrderType>

例子

var concurrentBag = new ConcurrentBag<OrderType>();


// make first call
// add results to concurrentBag
// pass the pageCount to the for
int pagesize = ...;

Parallel.For(1, pagesize,
   page =>
      {
         // Set up
         // add page
         // make Call 

         foreach(var order in getOrders.ApiResponse)
            concurrentBag.Add(order);
      });

// all orders have been downloaded
// save to db

注意MaxDegreeOfParallelism您可以配置它,也许将其设置为 50,尽管您给它多少并不重要,任务计划程序不会积极地给您线程,最初可能是 10 左右,并且增长缓慢。

您可以这样做的另一种方法是创建自己的Task Scheduler,或者只是使用老式ThreadClass启动您自己的 Threads


我在某处读过我想避免将 API 调用和 db 写入结合起来以避免锁定 SQL Server - 这是正确的吗?

  • 如果您的意思是在慢速数据库插入中锁定,请使用 Sql Bulk Insert 和更新工具。
  • 如果您的意思是像 DB 死锁错误消息中那样锁定,那么这是完全不同的事情,值得提出自己的问题

其他资源

For(Int32, Int32, ParallelOptions, 动作)

执行 for(在 Visual Basic 中为 For)循环,其中可以并行运行迭代并且可以配置循环选项。

ParallelOptions 类

存储配置 Parallel 类上方法操作的选项。

MaxDegreeOfParallelism

获取或设置此 ParallelOptions 实例启用的最大并发任务数。

ConcurrentBag 类

表示一个线程安全的、无序的对象集合。


推荐阅读