c# - CloudBlockBlob.DownloadToStream 与 DownloadRangeToStream

标签 c# asp.net azure azure-blob-storage azure-sdk-.net

尝试使用 ASP.NET azure SDK 从 Blob 存储下载图像。

我在另一篇文章中读到,DownloadToStream 确实将 blob 分解成更小的 block 并并行下载它们以提高性能。我相信这就是 DownloadRangeToStream 的用途。

我无法找到任何文档或代码来确认有关 DownloadToStream 的这一说法,并且对此表示怀疑,因为它的运行时间与直接从 blob url 下载相同(每次下载 0.5-3 秒)。这是我的两种下载方法的代码,提供了大致相同的性能。

使用 CloudBlockBlob.DownloadToStream:

private Bitmap DownloadFromBlob(String set) {

    CloudStorageAccount storageAccount = CloudStorageAccount.Parse( CloudConfigurationManager.GetSetting("StorageConnectionString"));

    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    CloudBlobContainer container = blobClient.GetContainerReference("templates");

    CloudBlockBlob blockBlob = container.GetBlockBlobReference(set + ".png");

    using (var memoryStream = new MemoryStream()) {
        blockBlob.DownloadToStream(memoryStream);

        return (memoryStream == null) ? null : (Bitmap)Image.FromStream(memoryStream);
    }
}

使用 Image.FromStream:

private Bitmap DownloadImageFromUrl(string url) {
    try {
        using (WebClient client = new WebClient()) {
            byte[] data = client.DownloadData(url);
            using (MemoryStream mem = (data == null) ? null : new MemoryStream(data)) {
                return (data == null || mem == null) ? null : (Bitmap)Image.FromStream(mem);
            }
        }
    } catch (WebException e) {
        return null;
    }
}

我正在尝试增加 0.5-12 MB 图像的下载时间。我尝试为这些图像实现我自己的 DownloadRangeToStream 方法,其代码如下。我是否需要执行此操作,还是 DownloadToStream 已经为我执行此操作?此方法产生与上面的 DownloadFromBlob 方法相同的运行时..

使用 downloadRangeToStream:

private Image getImageFromStream(string set)
    {
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
        CloudConfigurationManager.GetSetting("StorageConnectionString"));

        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        CloudBlobContainer container = blobClient.GetContainerReference("templates");

        CloudBlockBlob blockBlob = container.GetBlockBlobReference(set + ".png");

        using (MemoryStream ms = new MemoryStream())
        {

            ParallelDownloadBlob(ms, blockBlob);
            return (ms == null) ? null : Image.FromStream(ms);
        }
    }
private static void ParallelDownloadBlob(Stream outPutStream, CloudBlockBlob blob)
    {
        blob.FetchAttributes();
        int bufferLength = 1 * 1024 * 1024;//1 MB chunk
        long blobRemainingLength = blob.Properties.Length;
        Queue<KeyValuePair<long, long>> queues = new Queue<KeyValuePair<long, long>>();
        long offset = 0;
        while (blobRemainingLength > 0)
        {
            long chunkLength = (long)Math.Min(bufferLength, blobRemainingLength);
            queues.Enqueue(new KeyValuePair<long, long>(offset, chunkLength));
            offset += chunkLength;
            blobRemainingLength -= chunkLength;
        }
        Parallel.ForEach(queues,
            new ParallelOptions()
            {
        //Gets or sets the maximum number of concurrent tasks
        MaxDegreeOfParallelism = 10
            }, (queue) =>
            {
                using (var ms = new MemoryStream())
                {
                    blob.DownloadRangeToStream(ms, queue.Key, queue.Value);
                    lock (outPutStream)
                    {
                        outPutStream.Position = queue.Key;
                        var bytes = ms.ToArray();
                        outPutStream.Write(bytes, 0, bytes.Length);
                    }
                }
            });
    }

最佳答案

根据我的理解,CloudBlockBlob.DownloadToStreamImage.FromStream 只会发送下载流的请求,您可以利用 Fiddler捕获流量如下:

使用DownloadRangeToStream时,您可以将blob分解成更小的 block 并自行并行下载,以提高性能。这是我的代码片段,你可以引用一下。

private static void ParallelDownloadBlob(Stream outPutStream, CloudBlockBlob blob)
{
    blob.FetchAttributes();
    int bufferLength = 1 * 1024 * 1024;//1 MB chunk
    long blobRemainingLength = blob.Properties.Length;
    Queue<KeyValuePair<long, long>> queues = new Queue<KeyValuePair<long, long>>();
    long offset = 0;
    while (blobRemainingLength > 0)
    {
        long chunkLength = (long)Math.Min(bufferLength, blobRemainingLength);
        queues.Enqueue(new KeyValuePair<long, long>(offset, chunkLength));
        offset += chunkLength;
        blobRemainingLength -= chunkLength;
    }
    Parallel.ForEach(queues,
        new ParallelOptions()
        {   
            //Gets or sets the maximum number of concurrent tasks
            MaxDegreeOfParallelism = 10
        }, (queue) =>
            {
                using (var ms = new MemoryStream())
                {
                    blob.DownloadRangeToStream(ms, queue.Key, queue.Value);
                    lock (outPutStream)
                    {
                        outPutStream.Position = queue.Key;
                        var bytes = ms.ToArray();
                        outPutStream.Write(bytes, 0, bytes.Length);
                    }
                }
            });
}

结果:

此外,还有一些关于并行上传/下载 Blob 的博客,您可以引用它们( blog1blog2 )。

关于c# - CloudBlockBlob.DownloadToStream 与 DownloadRangeToStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41810485/

相关文章:

c# - ASP :NET MVC: How can I render two styles in one page without any overlaps of CSS classes?

c# - 在 C# 中异步创建新 DocumentDB 文档的问题

azure - 在 azure 上通过 Terraform 安装 DC/OS 时无法覆盖提供程序配置错误

c# - ASP.NET MVC HTML 转义

c# - 无法在 ASP.NET Core 1 应用程序中使用 Oracle 托管驱动程序

c# - 如何在 gridview 中查找特定行的值?

asp.net - vs2013 azure web 部署失败并显示未知的 ProviderOption :DefiningProjectFullPath

azure - 什么时候不应该使用 ACS?

c# - 如何在日历中捕获选定日期更改事件?

c# - 为什么 is type/is var 对 null 产生不同的结果?