Exemple #1
0
        /// <summary>
        /// 开始下载文件
        /// </summary>
        /// <returns></returns>
        public async Task DownloadFile()
        {
            _logger.LogInformation($"Start download Url={Url} File={File.FullName}");

            var(response, contentLength) = await GetContentLength();

            FileStream = File.Create();
            FileStream.SetLength(contentLength);
            FileWriter = new RandomFileWriter(FileStream);

            SegmentManager = new SegmentManager(contentLength);

            _progress.Report(new DownloadProgress($"file length = {contentLength}", SegmentManager));

            var downloadSegment = SegmentManager.GetNewDownloadSegment();

            // 下载第一段
            Download(response, downloadSegment);

            var supportSegment = await TryDownloadLast(contentLength);

            var threadCount = 1;

            if (supportSegment)
            {
                // 多创建几个线程下载
                threadCount = 10;

                for (var i = 0; i < threadCount; i++)
                {
                    Download(SegmentManager.GetNewDownloadSegment());
                }
            }

            for (var i = 0; i < threadCount; i++)
            {
                _ = Task.Run(DownloadTask);
            }

            await FileDownloadTask.Task;
        }
        /// <summary>
        /// 网速控制开关
        /// </summary>
        /// <returns></returns>
        private async void ControlSwitch()
        {
            // 使用独立的线程的优势在于不需要等待下载就能进入方法
            // 可以干掉 LastTime 属性,因此定时是 3 秒
            await Task.Delay(ControlDelayTime);

            while (!SegmentManager.IsFinished())
            {
                LogDebugInternal("Start ControlSwitch");
                var(segment, runCount, maxReportTime) = SegmentManager.GetDownloadSegmentStatus();
                int waitCount = DownloadDataList.Count;

                LogDebugInternal("ControlSwitch 当前等待数量:{0},待命最大响应时间:{1},运行数量:{2},运行线程{3}", waitCount, maxReportTime, runCount, _threadCount);

                if (maxReportTime > TimeSpan.FromSeconds(10) && segment != null && runCount > 1)
                {
                    // 此时速度太慢
                    segment.LoadingState = DownloadingState.Pause;
                    LogDebugInternal("ControlSwitch slowly pause segment={0}", segment.Number);
                }
                else if (maxReportTime < TimeSpan.FromMilliseconds(600) && waitCount > 0 || runCount < 1)
                {
                    // 速度非常快,尝试再开线程,或者当前没有在进行的任务
                    // 如果此时是刚好全部完成了,而 runCount 是 0 进入 StartDownloadTask 也将会啥都不做
                    LogDebugInternal("ControlSwitch StartDownloadTask");

                    // 这里不需要线程安全,如果刚好全部线程都在退出,等待 ControlDelayTime 再次创建
                    if (_threadCount < MaxThreadCount)
                    {
                        StartDownloadTask();
                    }
                }

                LogDebugInternal("Finish ControlSwitch");
                //变速器3秒为一周期
                await Task.Delay(ControlDelayTime);
            }
        }
        /// <summary>
        /// 开始下载文件
        /// </summary>
        /// <returns></returns>
        public async Task DownloadFileAsync()
        {
            _logger.LogInformation($"Start download Url={Url} File={File.FullName}");

            var(response, contentLength) = await GetContentLength();

            _logger.LogInformation($"ContentLength={contentLength}");

            if (contentLength < 0)
            {
                // contentLength == -1
                // 当前非下载内容,没有存在长度
                // 可测试使用的链接是 https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-5.0.100-preview.7-windows-x64-installer
                _logger.LogWarning($"Can not download file. ContentLength={contentLength}");
                return;
            }

            FileStream = File.Create();
            FileStream.SetLength(contentLength);
            FileWriter = new RandomFileWriterWithOrderFirst(FileStream);
            FileWriter.StepWriteFinished += (sender, args) => SharedArrayPool.Return(args.Data);

            SegmentManager = new SegmentManager(contentLength);

            _progress.Report(new DownloadProgress($"file length = {contentLength}", SegmentManager));

            var downloadSegment = SegmentManager.GetNewDownloadSegment();

            // 下载第一段
            Download(response, downloadSegment !);

            var supportSegment = await TryDownloadLast(contentLength);

            int threadCount;

            if (supportSegment)
            {
                // 先根据文件的大小,大概是 1M 让一个线程下载,至少需要开两个线程,最多是 10 个线程
                threadCount = Math.Max(Math.Min(2, (int)(contentLength / 1024 / 1024)), MaxThreadCount);
            }
            else
            {
                // 不支持分段下载下,多个线程也没啥用
                threadCount = 1;
            }

            if (supportSegment)
            {
                // 多创建几个线程下载
                for (var i = 0; i < threadCount; i++)
                {
                    Download(SegmentManager.GetNewDownloadSegment());
                }

                //控制开关,如果下载阻塞就先暂停
                ControlSwitch();
            }

            // 一开始就创建足够量的线程尝试下载
            for (var i = 0; i < threadCount; i++)
            {
                StartDownloadTask();
            }

            await FileDownloadTask.Task;
        }
Exemple #4
0
 public DownloadProgress(string message, SegmentManager segmentManager)
 {
     Message        = message;
     SegmentManager = segmentManager;
 }
Exemple #5
0
 public DownloadProgress(SegmentManager segmentManager)
 {
     SegmentManager = segmentManager;
 }