等待数据时的 `WaitAll()` 或 `WhenAll`
`WaitAll()` or `WhenAll` when expecting data
我从未尝试在 运行 async
功能时使用 WaitAll()
或 WhenAll()
。在查看了许多文档、SO 帖子和教程之后,我还没有找到足够的信息,所以我来了。
我正在尝试找出 best/proper 方法来执行以下操作:
使用 EF6,获取数据为 List<Entity>
。
遍历每个 Entity
并调用外部 API 来执行某些操作。
每个 Entity
的外部 API returns 数据我需要存储在同一个 Entity
.
目前我已经构建(未测试)以下(没有错误处理代码):
public IEnumerable<Entity> Process() {
bool hasChanged = false;
var data = _db.Entity.Where(x => !x.IsRegistered);
foreach (var entity in data) {
var result = await CallExternalApi(entity.Id, entity.Name);
entity.RegistrationId = result.RegistrationId;
entity.IsRegistered = true;
_db.Entry(entity).State = EntityState.Modified;
hasChanges = true;
}
if (hasChanges) {
uow.Commit();
}
return data;
}
我觉得我可以利用 async
中的其他一些 functionality/feature,但如果可以的话,我不确定如何在这里实现它。
非常感谢任何指导。
更新
我正在呼叫的 API 是用于添加注册人的 Zoom Api。虽然他们确实有批量添加注册人的途径,但它没有 return 我需要的 RegistrantId 和 Join Url。
首先,确定您的外部 API 是否有办法批量获取您想要的所有项目。如果是,请使用它而不是发送一大堆请求。
如果您需要为每个项目发送一个单独的请求,但又想同时进行,您可以这样做:
public async Task<IReadOnlyCollection<Entity>> Process() {
var data = _db.Entity.Where(x => !x.IsRegistered).ToList();
if(!data.Any()) { return data; }
var entityResultTasks = data
.Select(async entity => new { entity, result = await CallExternalApi(entity.Id, entity.Name) })
.ToList();
var entityResults = await Task.WhenAll(entityResultTasks);
foreach (var entityResult in entityResults) {
var entity = entityResult.entity;
var result = entityResult.result;
entity.RegistrationId = result.RegistrationId;
entity.IsRegistered = true;
_db.Entry(entity).State = EntityState.Modified;
}
uow.Commit();
return data;
}
您需要注意目标源上可能存在的并发限制。考虑使用 Chunk 将您的工作分成大小可接受的批次,或利用信号量或其他东西来限制您进行的调用次数。
我从未尝试在 运行 async
功能时使用 WaitAll()
或 WhenAll()
。在查看了许多文档、SO 帖子和教程之后,我还没有找到足够的信息,所以我来了。
我正在尝试找出 best/proper 方法来执行以下操作:
使用 EF6,获取数据为 List<Entity>
。
遍历每个 Entity
并调用外部 API 来执行某些操作。
每个 Entity
的外部 API returns 数据我需要存储在同一个 Entity
.
目前我已经构建(未测试)以下(没有错误处理代码):
public IEnumerable<Entity> Process() {
bool hasChanged = false;
var data = _db.Entity.Where(x => !x.IsRegistered);
foreach (var entity in data) {
var result = await CallExternalApi(entity.Id, entity.Name);
entity.RegistrationId = result.RegistrationId;
entity.IsRegistered = true;
_db.Entry(entity).State = EntityState.Modified;
hasChanges = true;
}
if (hasChanges) {
uow.Commit();
}
return data;
}
我觉得我可以利用 async
中的其他一些 functionality/feature,但如果可以的话,我不确定如何在这里实现它。
非常感谢任何指导。
更新
我正在呼叫的 API 是用于添加注册人的 Zoom Api。虽然他们确实有批量添加注册人的途径,但它没有 return 我需要的 RegistrantId 和 Join Url。
首先,确定您的外部 API 是否有办法批量获取您想要的所有项目。如果是,请使用它而不是发送一大堆请求。
如果您需要为每个项目发送一个单独的请求,但又想同时进行,您可以这样做:
public async Task<IReadOnlyCollection<Entity>> Process() {
var data = _db.Entity.Where(x => !x.IsRegistered).ToList();
if(!data.Any()) { return data; }
var entityResultTasks = data
.Select(async entity => new { entity, result = await CallExternalApi(entity.Id, entity.Name) })
.ToList();
var entityResults = await Task.WhenAll(entityResultTasks);
foreach (var entityResult in entityResults) {
var entity = entityResult.entity;
var result = entityResult.result;
entity.RegistrationId = result.RegistrationId;
entity.IsRegistered = true;
_db.Entry(entity).State = EntityState.Modified;
}
uow.Commit();
return data;
}
您需要注意目标源上可能存在的并发限制。考虑使用 Chunk 将您的工作分成大小可接受的批次,或利用信号量或其他东西来限制您进行的调用次数。