我正在编写一个必须通过SDK从外部api提取数据的程序。我不太熟悉await / async操作-但是知道每个调用的SDK提供了Async方法。 GetResultsAsync<TObject>()
每个查询都有返回的记录数限制-因此,要获取该月的所有记录-我必须按ID排序并循环。这是当前“同步”调用的一些示例代码。只要得到结果,我就会检查更多。
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;
}
这最多可以说4-5个循环(或更多取决于日期),但是显然很耗时。
如果我仅将其转换为async
方法-是否可以同时进行其他同步调用?假设我还需要在同一时间段获取服务凭单和项目凭单-但在返回所有凭单之前,不执行任何逻辑处理。我可以让所有三个呼叫异步运行吗?
这是目标
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.
如何实现?
对于示例#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;
}
或者实际上使用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;
}
虽然我了解到这些方法在内部仍在同步运行-我希望每次对ListTimeEntries
,ListServiceTickets
和ListProjectTickets
的调用都是异步发生的,以加快速度。
我想我的想法/希望-由于缺乏知识-将是每个同步调用将使用不同的线程-从而加快了整个过程。我离基地远吗?
答案 0 :(得分:0)
我会做类似以下的事情。您将需要了解有关API限制的潜在问题,并且当然有可能在所有4个线程完成之前至少有3个额外的请求正在进行中-如果要检索的页面很多,则要付出很小的代价。 / p>
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();
}