c# - 从异步调用收集响应时使用的数据结构
问题描述
我在我的应用程序中运行这段代码。
public Task<BulkResponse<JObject>> GetRelatedObjectsAsync(IEnumerable<PrimaryObjectInfo> primaryObjectInfos)
{
var allSecondaries = new List<Tuple<int, List<JObject>>>();
var exceptionsDict = new ConcurrentDictionary<int, Exception>();
var relatedObjectsTasks = primaryObjectInfos.Select(async primaryObjectInfo =>
{
try
{
var secondaryObject = await objectManager.GetRelatedObjectsAsync(primaryObjectInfo);
allSecondaries.Add(Tuple.Create(primaryObjectInfo.Index, secondaryObject.ToList()));
}
catch (Exception ex)
{
exceptionsDict.TryAdd(primaryObjectInfo.Index, ex);
}
});
await Task.WhenAll(relatedObjectsTasks);
return ConvertToBulkResponse(allSecondaries, exceptionsDict);
}
当我运行此代码allSecondaries
对象时,有时会返回有效的结果列表,有时代码最终会为每个primaryObjectInfo
.
Async 方法objectManager.GetRelatedObjectsAsync()
内部调用了 4-5 个异步函数,并且有些函数是通过引用传递参数的。(参考关键字)
问题: 我是否使用正确的数据结构来整合所有并行线程的结果?如果是,我每次得到不同结果的原因可能是什么?
解决方案
您最好将执行与结果收集分开:
public Task<BulkResponse<JObject>> GetRelatedObjectsAsync(
IEnumerable<PrimaryObjectInfo> primaryObjectInfos)
{
var relatedObjectsTasks = primaryObjectInfos
.Select(
async primaryObjectInfo =>
(primaryObjectInfo.Index,
await objectManager.GetRelatedObjectsAsync(primaryObjectInfo)))
.ToList();
try
{
await Task.WhenAll(relatedObjectsTasks);
}
catch
{
// observe each task's, exception
}
var allSecondaries = new List<(int index, List<JObject> related)>();
var exceptionsDict = new Dictionary<int, Exception>();
foreach (var relatedObjectsTask in relatedObjectsTasks)
{
try
{
allSecondaries.Add(relatedObjectsTask.Result);
}
catch (Exception ex)
{
exceptionsDict.Add(relatedObjectsTask.index, ex);
}
}
return ConvertToBulkResponse(allSecondaries, exceptionsDict);
}
您可以查看每个任务的IsFaulted
/Exception
和IsCancelled
属性,而不是引发异常:
foreach (var relatedObjectsTask in relatedObjectsTasks)
{
if (relatedObjectsTask.IsCancelled)
{
exceptionsDict.Add(
relatedObjectsTask.index,
new TaskCancelledException(relatedObjectsTask));
}
else if (relatedObjectsTask.IsFaulted)
{
exceptionsDict.TryAdd(relatedObjectsTask.index, ex);
}
else
{
allSecondaries.Add(relatedObjectsTask.Result);
}
}
推荐阅读
- c# - PowerShell:为什么我能够在一个会话中加载同一个 .NET 程序集的多个版本并“绕过依赖地狱”?
- django - Django 无法在视图类的方法中获取 model.objects 数据
- javascript - 脚本标签不打印任何消息
- python - 使用 Webbrowser 模块时出现 Chrome 路径文件问题(非个人问题)
- entity - 多个地址作为实体或值对象?
- javascript - 计算数组和正则表达式中每个项目的出现次数
- vulkan - Vulkan 并行渲染是否依赖于多个队列?
- wordpress - 如何在高负载时间减少 POST 和 GET 队列?
- python - 当我从动作中删除 python 生成的关键帧时,Blender 姿势(lib)会消失
- dataweave - 如何使用 dataweave 2.0 基于数组中的特定列添加数据