【问题标题】:Download blobs from azure storage asynchronously and save them in DataTable从 azure 存储异步下载 blob 并将它们保存在 DataTable 中
【发布时间】:2015-05-18 18:06:17
【问题描述】:

以下代码显示了我如何从 azure blob 存储下载 blob 并将它们保存到 DataTable 中:

foreach (var currIndexGroup in blobsGroupedByIndex)
{
    DataRow dr = dtResult.NewRow();
    foreach (var currIndex in currIndexGroup)
    {       
        long fileByteLength = currIndex.Properties.Length;
        byte[] serializedAndCompressedResult = new byte[fileByteLength];
        currIndex.DownloadToByteArray(serializedAndCompressedResult, 0);
        dr[currIndex.Metadata["columnName"]] = DeflateStream.UncompressString(serializedAndCompressedResult);
    }
    dtResult.Rows.Add(dr);
}

问题是,下载速度很慢。下载 1000 个真正的小 Blob 大约需要 20 秒。如果我尝试使用currIndex.DownloadToByteArrayAsync(serializedAndCompressedResult, 0); 异步运行它,后续行会抛出异常Bad state (invalid stored block lengths)

异步填充这个数据表的正确方法是什么?

【问题讨论】:

  • 你能用DownloadToByteArrayAsync添加你的代码吗?
  • 这是相同的代码,但使用的是 DownloadToByteArrayAsync 而不是 DownloadToByteArray。我猜它不起作用,因为后续行在执行时没有填充 serializedAndCompressedResult 。但是不知道怎么解决。
  • 你知道DataTable 不是线程安全的吗?为什么不使用ConcurrentDictionary

标签: c# azure asynchronous datatable


【解决方案1】:
//the plan here is to make a model that holds your currIndex and byte array so you can return that model from a task
public class MyModel 
{
    public CloudBlockBlob CurrIndex {get;set;} 
    public byte[] FileBytes {get;set;}
}



foreach (var currIndexGroup in blobsGroupedByIndex)
{

    var myTasks = new List<Task<MyModel>>();
    foreach (var currIndex in currIndexGroup)
    {     
        myTasks.Add(Task<MyModel>.Factory.StartNew(() => 
        {
            var myModel = new MyModel();
            myModel.CurrIndex = currIndex;

            long fileByteLength = myModel.CurrIndex.Properties.Length;
            myModel.FileBytes = new byte[fileByteLength];
            currIndex.DownloadToByteArray(myModel.FileBytes, 0);
            return myModel;
        });
    }
    Task.WaitAll(myTasks.ToArray());

    foreach (var task in myTasks)
    {
        MyModel myModel = task.Result;
        DataRow dr = dtResult.NewRow();
        dr[myModel.CurrIndex.Metadata["columnName"]] = DeflateStream.UncompressString(myModel.FileBytes);
        dtResult.Rows.Add(dr);
    }
}

您可以通过在外部 foreach 循环上使用 Parallel.ForEach 来进一步提高并行性。您必须锁定您的dtResult 以使其线程安全。

【讨论】:

  • 我在 myTasks.Add(Task.Factory.StartNew(async () => ... " Btw: CurrIndex 的数据类型是 CloudBlockBlob。
  • 对不起,我从中删除了异步,这在这种情况下可能无论如何都没有帮助。
  • 谢谢。我不得不添加 Task.WaitAll(myTasks.ToArray());为了让它工作,我添加了 Parallel.ForEach。现在速度更快了!
猜你喜欢
  • 2018-08-03
  • 2013-02-26
  • 2019-12-19
  • 2019-09-05
  • 2012-12-08
  • 1970-01-01
  • 2021-12-08
  • 2018-11-21
相关资源
最近更新 更多