将缓冲区写入响应流或长时间运行请求结束?

时间:2017-04-05 19:04:57

标签: .net asp.net-mvc asp.net-core asp.net-core-mvc .net-core

以下是运行.NET Framework的ASP.NET Core API。这是我的MVC控制器之一。

我必须从外部服务获取数据,这样我一次只能获得相当小的数据缓冲区 - 我无法控制这一点。假设我每个缓冲区得到500行数据,但是我的客户希望一次将所有数据格式化为CSV,所以我必须循环调用外部源,如下所示:

[HttpGet]
public async Task<IActionResult> Get(MyRequest request)
{
    var aggregateResponse = await client.GetDataAsync(request);
    while (aggregateResponse.HasMoreData)
    {
        request.Cookie = aggregateResponse.Cookie;
        var response = await client.GetDataAsync(request);
        //Data is a list of objects containing n number of properties
        aggregateResponse.Data.Concat(response.Data)

        //I need the cookie from the previous response to get the next buffer
        aggregateResponse.Cookie = response.Cookie;
        aggregateResponse.HasMoreData = response.HasMoreData;
    }
    //runs through a generic IEnumerable CSV output formatter (uses reflection)
    return Ok(aggregateResponse.Data);
}

可悲的是,这可能需要100-200个循环来获取所有数据(在aggregateResponse.Data中有50,000到100,000个列表项),但我没有太多选择。

  • 将每个数据缓冲区格式化为循环中的CSV并将其每次写入响应流是否更有效,或者更好地等到结束,就像我现在正在做的那样?例如:

    [HttpGet]
    public async Task<IActionResult> Get(MyRequest request)
    
    {
        var response = await client.GetDataAsync(request);
        await Response.WriteAsync(formatBeginningData(response.Data))
        while (request.HasMoreData)
        {
            request.Cookie = aggregateResponse.Cookie;
            response = await client.GetDataAsync(request);
            await Response.WriteAsync(formatData(response.Data))
            request.Cookie = response.Cookie;
            request.HasMoreData = response.HasMoreData;
        }
    
        return Ok();
    }
    
  • 我在这种方法中不断使用异步进行数据调用,但这意味着线程将会转换很多次。异步这样做实际上给我的性能下降了吗?它应该是同步的(方法签名和数据调用)吗?

1 个答案:

答案 0 :(得分:1)

  

将每个数据缓冲区格式化为循环中的CSV并将其每次写入响应流会更高效,还是更好地等到我现在正在做的结束?

您可以,但我不推荐它,除非数据太大而无法放入内存。

流媒体的优点是数据不必适合内存,客户端可以零碎地接收数据。

流式传输的缺点是HTTP响应代码必须在流式传输开始之前发送,因此在流式传输开始后无法通知客户端错误。因此,如果对GetDataAsync的其中一个调用失败,客户端仍会获得200 OK,但其数据会被意外切断。

  

我在这种方法中不断使用异步进行数据调用,但这意味着线程将会很多次切换。异步这样做实际上给我的性能下降了吗?它应该是同步的(方法签名和数据调用)吗?

没有; ASP.NET Core上的异步代码与同步代码具有相同或更少的线程切换。