【发布时间】:2018-11-09 16:39:51
【问题描述】:
我正在编写一个必须通过 SDK 从外部 api 提取数据的程序。我不精通等待/异步操作 - 但知道每个调用的 SDK 都提供了一个异步方法。 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.
如何实现?
对于 example #1 - 只是将 Method 设置为 async 工作吗?例如:
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 时都异步进行以加快速度。
我想我的想法/希望 - 由于缺乏知识 - 每个同步调用都将使用不同的线程 - 从而加快整个过程。我离基地很远吗?
【问题讨论】:
-
这是什么应用程序?
api.GetEntries是否绑定了 I/O,它是否返回Task<T>?这两个问题决定了使用async/await是否有好处以及是否可以使用async/await。至于您最终设想的调用代码,您必须检查 api 是否也是线程安全的(支持多个同时调用)。并非所有 API 都像 Entity Framework 的DbContext那样。 -
@Igor - 是的,
api.GetEntries将返回一个Task<T>- 因为执行它的GetResultsAsync<T>调用。 -
那么代码应该是
var newItems = await api.GetEntries(...并将async关键字添加到调用它的方法签名中,并让它也返回一个Task<T>。 -
仅供参考,在您等待每个电话的“这是目标”部分。这意味着第二次调用将在第一次调用完成之前运行,第三次调用直到第二次调用。如果您希望它们全部同时发生,然后等待它们全部完成,您需要等待
Task.WhenAll传入您的三个任务 -
@Igor 对不起,我误读了代码,这是一个漫长的星期五。 OP请忽略我的评论
标签: c# loops asynchronous async-await