C#将异步写入特定数据大小

时间:2017-05-04 12:19:14

标签: c# api asynchronous buffer

我在C#中有一个API,它从数据库和在表格中绘制数据的前端返回数据。

我的方法是使用sqlReader从DB读取数据,遍历此读取器将每个结果添加到列表中并将该列表返回到前端。

似乎很容易,直到我收到大量的查询数据。我的解决方案是按块恢复这个数据块,但我坚持使用它,这是我正在使用的代码:

 var sqlCommand = db.InitializeSqlCommand(query);
                try
                {
                    using (var reader = sqlCommand.ExecuteReader())
                    {
                        var results = new List<List<string>>();
                        var headers = new List<string>();
                        var rows = new List<string>();
                        for (var i = 0; i < reader.FieldCount; i++)
                        {
                            headers.Add(reader.GetName(i));
                        }
                        results.Add(headers);
                        while (reader.Read())
                        {
                            for (var i = 0; i < reader.FieldCount; i++)
                            {
                                rows.Add((reader[reader.GetName(i)]).ToString());
                            }
                            results.Add(rows);
                            var str = JsonConvert.SerializeObject(results);
                            var buffer = Encoding.UTF8.GetBytes(str);

                            //Thread.Sleep(1000);
                            await outputStream.WriteAsync(buffer, 0, buffer.Length);
                            rows.Clear();
                            results.Clear();
                            outputStream.Flush();

                        }
                    }
                }
                catch (HttpException ex)
                {
                    if (ex.ErrorCode == -2147023667) // The remote host closed the connection. 
                    {
                    }
                }
                finally
                {
                    outputStream.Close();
                    db.Dispose();
                }

有了这个,我就可以逐个返回数据(用Thread.sleep测试),但我仍然坚持如何返回一个特定的数量,比如200个数据或者1000,这真的不重要。

关于如何进行的任何想法? 提前致谢。 MESE。

1 个答案:

答案 0 :(得分:2)

我认为控制查询是更好的方法,因为这将是从数据库中获取的内容。您可以为每次后续运行增加OFFSET。示例 - 在ORDER BY子句之后添加OFFSET 200 ROWS FETCH NEXT 200 ROWS ONLY以跳过200行并获得下一个200.

但是,由于您已经提到您无法控制查询,因此您可以执行类似的操作来过滤我们的结果。这里的关键技巧是使用reader.AsEnumerable.Skip(200).Take(200)来选择要处理的行。在每次迭代中将输入更新为Skip()以相应地处理数据。

// Offset variable will decide how many rows to skip, the outer while loop can be
// used to determine if more data is present and increment offset by 200 or any
// other value as required. Offset -> 0, 200, 400, 600, etc.. until data is present

bool hasMoreData = true;
int offset = 0;
while(hasMoreData)
{
    // SQL Data reader and other important operations
    foreach(var row in reader.AsEnumerable.Skip(offset).Take(200)) 
    { 
        // Processing operations
    }
    // Check to ensure there are more rows
    if(no more rows)
        hasMoreData = false;
    offset += 200;
}

另外要记住的是,当您批量提取数据时,查询将多次执行,如果在此期间添加或删除了新记录,则批次将无法正常运行。为了解决这个问题,你可以做两件事:

  • 使用已获取记录的唯一ID验证每条记录的唯一ID,以确保不会拉出相同的记录两次(由于记录添加/删除而导致的边缘情况)
  • 向您的偏移量添加缓冲区,例如
    • Skip(0).Take(100) //拉0到100条记录
    • Skip(90).Take(100) //拉出90 - 190条记录(重叠10条以满足添加/删除)
    • Skip(180).Take(100) //拉出180 - 280条记录(重叠10条以满足添加/删除)
    • 等......

希望这有帮助!