You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化C#中依赖GetMyData的OData扩展操作以降低延迟?

优化方案:并行主数据与扩展数据查询

核心优化思路是将主数据查询(GetMyData)与扩展数据查询并行执行——原流程是串行执行主查询+并行扩展查询,总耗时为主查询时间 + 最长扩展查询时间;优化后改为并行执行两类查询,总耗时缩短为max(主查询时间, 最长扩展查询时间),直接降低整体延迟。

具体实现步骤

  • 拆分扩展操作:把AppendExpandOption1DataAsync/AppendExpandOption2DataAsync拆分为「数据查询」和「结果填充」两个独立部分,让查询逻辑可以提前启动,无需等待主数据转换完成。
  • 并行启动任务:在拿到主查询所需的identifierId/identifierName后,同时启动主数据查询和对应扩展项的数据查询任务。
  • 错误关联处理:用CancellationToken关联主查询与扩展查询,主查询失败时自动取消扩展查询,避免无效数据库调用。

优化后代码示例

public async Task<ResponseType> GetDataAsync(
    RequestType request,
    ODataQueryOptions<ResponseType>? options = null,
    string? version = null,
    CancellationToken cancellationToken = default)
{
    if (request == null)
        throw new ArgumentNullException(nameof(request));

    // 提前解析OData扩展选项
    IEnumerable<ExpandedNavigationSelectItem>? expandOptions = options?.SelectExpand?.SelectExpandClause.SelectedItems.OfType<ExpandedNavigationSelectItem>();

    (string identifierName, string identifierId) = Utils.GetIdentifier(request);

    // 并行启动主数据查询和扩展数据查询任务
    var mainDataTask = dataApiClient.GetMyData(identifierId, identifierName, version, cancellationToken);
    var expandQueryTasks = new List<Task>();
    var expandFillOperations = new List<Action<ResponseType>>();

    foreach (var item in expandOptions ?? Enumerable.Empty<ExpandedNavigationSelectItem>())
    {
        var segmentName = item.PathToNavigationProperty.FirstSegment.Identifier;
        if (segmentName.Equals("ExpandOption1", StringComparison.CurrentCultureIgnoreCase))
        {
            // 先启动扩展1的数据查询,查询完成后暂存结果,后续填充到response
            ExpandOption1Type? option1Data = null;
            expandQueryTasks.Add(GetExpandOption1DataAsync(identifierId, identifierName, version, cancellationToken)
                .ContinueWith(t => option1Data = t.Result, cancellationToken));
            expandFillOperations.Add(response => response.ExpandOption1 = option1Data);
        }
        else if (segmentName.Equals("ExpandOption2", StringComparison.CurrentCultureIgnoreCase))
        {
            ExpandOption2Type? option2Data = null;
            expandQueryTasks.Add(GetExpandOption2DataAsync(identifierId, identifierName, version, cancellationToken)
                .ContinueWith(t => option2Data = t.Result, cancellationToken));
            expandFillOperations.Add(response => response.ExpandOption2 = option2Data);
        }
    }

    // 等待主数据查询完成(若主查询失败,直接抛出异常,扩展任务会被取消)
    DataPreview dataPreview = await mainDataTask;
    ResponseType response = dataPreview.ConvertToResponse();

    // 等待所有扩展查询完成,再将结果填充到response
    if (expandQueryTasks.Count > 0)
    {
        await Task.WhenAll(expandQueryTasks);
        foreach (var fillOp in expandFillOperations)
        {
            fillOp(response);
        }
    }

    return response;
}

// 拆分后的扩展数据查询方法(仅负责数据库调用)
private async Task<ExpandOption1Type> GetExpandOption1DataAsync(string identifierId, string identifierName, string? version, CancellationToken cancellationToken)
{
    // 此处替换为原AppendExpandOption1DataAsync中的数据库查询逻辑
    return await dataApiClient.FetchExpandOption1Data(identifierId, identifierName, version, cancellationToken);
}

// 拆分后的扩展数据查询方法(Option2同理)
private async Task<ExpandOption2Type> GetExpandOption2DataAsync(string identifierId, string identifierName, string? version, CancellationToken cancellationToken)
{
    return await dataApiClient.FetchExpandOption2Data(identifierId, identifierName, version, cancellationToken);
}

额外注意事项

  1. 无法拆分扩展方法的兼容方案:如果不能修改AppendExpandOptionXDataAsync(比如依赖外部组件),可以尝试和数据API团队沟通,提供批量获取主数据+扩展数据的接口,从根源减少数据库调用次数;不建议提前初始化空ResponseType占位,容易引入未初始化的空引用风险。
  2. 异常处理:原代码中GetMyData可能返回500/404,优化后需确保主查询抛出异常时,扩展任务能被及时取消,避免无效的资源占用。
  3. 代码可读性:替换原代码中的List.ForEach为foreach循环,便于调试和维护。

内容的提问来源于stack exchange,提问作者Programmerzzz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:36:05