简体   繁体   English

异步循环调用的异步方法的任何好处

[英]Any benefit to an Async method that Synchronously Loops a call

I'm writing a program that must pull data from an external api via an SDK. 我正在编写一个必须通过SDK从外部api提取数据的程序。 I'm not well versed in await/async operations - but know the SDK for each of the calls offers an Async method. 我不太熟悉await / async操作-但是知道每个调用的SDK提供了Async方法。 GetResultsAsync<TObject>()

Each query has a limit of records returned - so in order to get all records for the month - I must order by ID, and loop. 每个查询都有返回记录的限制-因此,为了获取该月的所有记录-我必须按ID排序,然后循环。 Here's some sample code of the current Synchronous calls out. 这是当前“同步”调用的一些示例代码。 As long as I get results - I check for more. 只要我得到结果-我就会检查更多。

public List<TimeEntry> ListTimeEntries(DateTime startDate, DateTime endDate)
{
    var page = 1;
    var hasMore = false;
    var qry = string.Format("timeStart >= [{0}] and timeEnd <= [{1}]", startDate, endDate); //For example
    var results = List<TimeEntry>();
    do
    {
        var newItems = api.GetEntries(qry, "id desc", maxPageSize, page).GetResults<List<TimeEntry>>();
        results.AddRange(newItems);
        hasMore = newItems.Any();
        page++;
    } while (hasMore);
    return results;
}

This could make up to say 4-5 loops (or more depending on dates), but is obviously time consuming. 这可能要说4-5个循环(或更多取决于日期),但显然很耗时。

If I simply convert this to an async method - would I be able to have other synchronous calls being made at the same time? 如果我将其简单地转换为async方法-是否可以同时进行其他同步调用? Let's assume I also need to get Service Tickets and Project Tickets for the same time period - but don't do any logical processing until all are returned. 假设我还需要在同一时间段获取服务凭单和项目凭单-但在返回所有凭单之前,不执行任何逻辑处理。 Could I have all three calls running asynchronously? 我可以让所有三个呼叫异步运行吗?

Here's the Goal 这是目标

var startDate = DateTime.Now.AddDays(-30);
var endDate = DateTime.Now;

var timeTask = ListTimeEntries(startDate, endDate);
var serviceTask = ListServiceTickets(startDate, endDate);
var projectTask = ListProjectTickets(startdDate, endDate);

var timeEntries = await timeTask;
var serviceTickets = await serviceTask;
var projectTickets = await projectTask;

// Do what ever processing logic I need now.

How to Achieve? 如何实现?

For example #1 - would simply making the Method as async work? 例如#1-会使方法作为async工作吗? EG: 例如:

public async Task<List<TimeEntry>> ListTimeEntries(DateTime startDate, DateTime endDate)
{
    var page = 1;
    var hasMore = false;
    var qry = string.Format("timeStart >= [{0}] and timeEnd <= [{1}]", startDate, endDate); //For example
    var results = List<TimeEntry>();
    do
    {
        var newItems = api.GetEntries(qry, "id desc", maxPageSize, page).GetResults<List<TimeEntry>>();
        results.AddRange(newItems);
        hasMore = newItems.Any();
        page++;
    } while (hasMore);
    return results;
}

Or would there be any benefit for actually using the SDK's GetResultsAsync<> method such as Example 2 : 或实际上使用SDK的GetResultsAsync<>方法(例如示例2)是否会有任何好处:

public async Task<List<TimeEntry>> ListTimeEntries(DateTime startDate, DateTime endDate)
{
    var page = 1;
    var hasMore = false;
    var qry = string.Format("timeStart >= [{0}] and timeEnd <= [{1}]", startDate, endDate); //For example
    var results = List<TimeEntry>();
    do
    {
        var newItemsTask = api.GetEntries(qry, "id desc", maxPageSize, page).GetResultsAsync<List<TimeEntry>>();
        var newItems = await newItemsTask;
        results.AddRange(newItems);
        hasMore = newItems.Any();
        page++;
    } while (hasMore);
    return results;
}

While I understand that these methods internally are still running Synchronously - I'm hoping to make each call to ListTimeEntries , ListServiceTickets , and ListProjectTickets happen asynchronously to speed up. 虽然我知道这些方法在内部仍在同步运行-我希望每次对ListTimeEntriesListServiceTicketsListProjectTickets调用都异步发生以加快速度。

I guess my thought/hope - with lack of knowledge - would be that each Synchronous call would utilize a different thread - thus speeding up the overall process. 我想/由于缺乏知识,我的想法/希望是每个同步调用将使用不同的线程,从而加快了整个过程。 Am I way off base? 我离基地远吗?

I'd do something like the following. 我会做类似以下的事情。 You will need to be aware of potential issues around API limits and of course there is the possibility for having at least three additional requests in-flight before all 4 threads complete - a small price to pay if you have lots of pages to retrieve. 您将需要了解有关API限制的潜在问题,并且当然有可能在所有4个线程完成之前至少有3个额外的请求正在进行中-如果要检索的页面很多,则要付出很小的代价。

public async Task<IList<TimeEntry>> CallSomething(DateTime startDate, DateTime endDate)
{
    var qry = string.Format("timeStart >= [{0}] and timeEnd <= [{1}]", startDate, endDate); //For example

    const threadCount = 4;

    var isComplete = new ManualResetEvent();
    var page = 0;
    var results = new ConcurrentBag<TimeEntry>();
    var thread = new Task[threadCount];
    for(var i = 0; i < threadCount; ++i)
    {
        thread[i] = Task.Run(
            async () =>
            {
                while(!isComplete.WaitOne(TimeSpan.Zero))
                {
                    var localPage = Interlocked.Increment(ref page);

                    var newItems = await api
                        .GetEntries(qry, "id desc", maxPageSize, localPage)
                        .GetResultsAsync<List<TimeEntry>>()
                        .ConfigureAwait(false);

                    if (!newItems.Any())
                    {
                        isComplete.Set();
                    }
                    else
                    {
                        foreach (var item in newItems)
                        {
                            results.Add(item);
                        }
                    }
                }
            })
        )
    }

    await Task.WhenAll(thread).ConfigureAwait(false);

    return results.OrderByDescending(f => f.Id).ToList();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM