C# 多线程上传程序

C# 多线程上传程序,c#,multithreading,azure,task-parallel-library,C#,Multithreading,Azure,Task Parallel Library,我想上传巨大的文件(2到40 GB)到Azure Blob存储 首先,我成功地将每个文件分割成块(每个块=2MB)。 然后我一个接一个地上传区块,在成功上传每个区块后,我更新一个临时文件,以便在应用程序关闭时能够继续上传 现在我想让上传操作多线程化。 回顾了第三方物流之后,我不知道从哪里开始 从哪里开始第三方物流有什么指导吗 void Upload(int segmentId) { try { string blockId = GetBlockId(segment

我想上传巨大的文件(2到40 GB)到Azure Blob存储

首先,我成功地将每个文件分割成块(每个块=2MB)。 然后我一个接一个地上传区块,在成功上传每个区块后,我更新一个临时文件,以便在应用程序关闭时能够继续上传

现在我想让上传操作多线程化。 回顾了第三方物流之后,我不知道从哪里开始

从哪里开始第三方物流有什么指导吗

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)
    {
        ...
    }
}

很久以前,我构建了类似的东西(虽然我使用异步方法而不是TPL),我想
上传具有可恢复功能的真正大的blob
。以下是我所做的:

  • 首先根据块大小,我将文件分为块。每个区块都分配了一个id。然后我创建了一个对象,该对象保存区块id和该区块的状态。为简单起见,我为块保留了以下状态—
    NotStarted
    Successful
    Failed
  • 然后我创建了这些块的集合,并将数据序列化到一个文件中
  • 基于并行线程的数量(比如x),我从状态为
    NotStarted
    的集合中获取x个项目。然后我并行处理这些块。我将区块id作为用户状态传递,以便在收到回拨时,根据上载状态相应地更新集合并序列化回数据
  • 上传完所有的区块后,我检查是否有任何失败的区块。如果有,我将重试这些块
  • 一旦所有块都成功完成,我只需从chunks集合创建一个块列表并提交该块列表。如果提交块列表操作成功,我只需删除包含块数据的文件
  • 希望这有帮助

    更新

    请务必查看此伪代码,看看这是否有助于您:

    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
        }
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用System.Linq;
    使用系统文本;
    使用System.Threading.Tasks;
    命名空间UploadLargeBlob
    {
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    List chunksToUpload=新建列表();
    CreateChunkCollection(“MyVeryLargeFile”,2*1024*1024);
    int numberOfParallelThreads=8;
    做
    {
    var chunksToProcess=chunksToUpload.Where(c=>c.Status==ChunkStatus.NotStarted | | c.Status==ChunkStatus.Failed);
    if(chunksToProcess.Count()==0)
    {
    打破
    }
    列表任务=新列表();
    尝试
    {
    foreach(chunksToProcess中的var chunk)
    {
    tasks.Add(Task.Factory.StartNew(()=>
    {
    双倍体;
    }组块);
    }
    Task.WaitAll(tasks.ToArray());
    }
    捕获(聚合异常例外)
    {
    foreach(任务中的var任务)
    {
    if(task.Exception!=null)
    {
    ChunkInformation chunk=task.AsyncState作为ChunkInformation;
    chunk.Status=ChunkStatus.Failed;
    //现在序列化数据。
    }
    }
    }
    }
    虽然(正确);
    }
    静态void双重加载(ChunkInformation chunk)
    {
    //进行实际上传
    //上传区块后更新区块状态
    chunk.Status=ChunkStatus.Successful;
    //序列化数据。
    }
    静态void CreateChunkCollection(字符串文件名,int chunkSize)
    {
    }
    }
    公共类信息
    {
    公共字符串Id
    {
    得到;
    设置
    }
    公共地位
    {
    得到;
    设置
    }
    }
    公共枚举块状态
    {
    没有开始,
    成功的
    失败
    }
    }
    
    提供一些代码,请告诉我您可用的上传带宽是多少???@RobertoBonini~8 Mbit如果第3段在第2段之前上传,会由服务器上的
    blockId
    来处理吗?@Belogix我有一个方法来处理段的顺序。这正是我所做的。我的问题是如何实现多线程?这是多线程的。Task.Factory.StartNew将新工作项添加到TPL的线程池工作项队列中。