多线程上传器

时间:2013-08-13 10:25:57

标签: c# multithreading azure task-parallel-library

我想将大文件(2到40 GB之间)上传到Azure Blob存储。

首先,我成功地将每个文件拆分为块(每个块= 2 MB)。 然后我逐个上传块,每个块上传成功后我更新临时文件,以便在应用程序关闭时恢复上传。

现在我想进行多线程上传操作。 在审查了TPL后,我很困惑从哪里开始!

从TPL开始的任何指导?

void Upload(int segmentId)
{
    try
    {
        string blockId = GetBlockId(segmentId);
        var segment = GetSegment(FilePath, segmentId, SeqmentSize);
        var md5Hash = CalcMd5Hash(segment);

        var blob = new CloudBlockBlob(_link.Uri);
        using (var memoryStream = new MemoryStream(segment))
        {
            blob.PutBlock(blockId, memoryStream, md5Hash);
        }

        SerializeStatus();
    }
    catch (Exception exception)
    {
        ...
    }
}

1 个答案:

答案 0 :(得分:3)

我建立了类似很长时间的东西(虽然我使用异步方法而不是TPL)我想要 upload really large blobs with resumable capability 。这是我做的:

  1. 首先根据块大小,我将文件拆分为块。每个块都分配了一个id。然后我创建了一个对象,它保存了块ID和该块的状态。为简单起见,我保留了以下状态 - NotStartedSuccessfulFailed
  2. 然后,我创建了这些块的集合,并将该数据序列化为文件。
  3. 根据并行线程的数量(比方说x),我从状态为NotStarted的集合中获取x个项目。然后我并行处理这些块。我将chunk id作为用户状态传递,这样当我收到回调时,根据上传状态,我会相应地更新集合并将数据序列化。
  4. 上传完所有块后,我检查是否有任何失败的块。如果有的话,我会重试那些块。
  5. 一旦成功完成所有块,我只需从块集合中创建一个块列表并提交该块列表。如果提交阻止列表操作成功,我只是删除了包含块数据的文件。
  6. 希望这有帮助。

    <强>更新

    请查看此伪代码,看看这是否对您有所帮助:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UploadLargeBlob
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<ChunkInformation> chunksToUpload = new List<ChunkInformation>();
                CreateChunkCollection("MyVeryLargeFile", 2*1024*1024);
                int numberOfParallelThreads = 8;
                do
                {
                    var chunksToProcess = chunksToUpload.Where(c => c.Status == ChunkStatus.NotStarted || c.Status == ChunkStatus.Failed).Take(numberOfParallelThreads);
                    if (chunksToProcess.Count() == 0)
                    {
                        break;
                    }
                    List<Task> tasks = new List<Task>();
                    try
                    {
                        foreach (var chunk in chunksToProcess)
                        {
                            tasks.Add(Task.Factory.StartNew(() =>
                                {
                                    DoUpload(chunk);
                                }, chunk));
                        }
                        Task.WaitAll(tasks.ToArray());
                    }
                    catch (AggregateException excep)
                    {
                        foreach (var task in tasks)
                        {
                            if (task.Exception != null)
                            {
                                ChunkInformation chunk = task.AsyncState as ChunkInformation;
                                chunk.Status = ChunkStatus.Failed;
                                //Now serialize the data.
                            }
                        }
                    }
                }
                while (true);
            }
    
            static void DoUpload(ChunkInformation chunk)
            {
                //Do the actual upload
    
                //Update chunk status once chunk is uploaded
                chunk.Status = ChunkStatus.Successful;
    
                //Serialize the data.
            }
    
            static void CreateChunkCollection(string fileName, int chunkSize)
            {
            }
        }
    
        public class ChunkInformation
        {
            public string Id
            {
                get;
                set;
            }
    
            public ChunkStatus Status
            {
                get;
                set;
            }
        }
    
        public enum ChunkStatus
        {
            NotStarted,
            Successful,
            Failed
        }
    }