如何使用 HttpWebRequest 获得文件并行

2024-01-01

我正在尝试制作一个像 IDM 这样的程序,它可以同时下载文件的部分内容。
我用来实现此目的的工具是 C# .Net4.5 中的 TPL
但是我在使用的时候遇到了问题Tasks使操作并行。
序列功能运行良好,并且正在正确下载文件。
使用任务的并行函数一直在工作,直到发生奇怪的事情:
我创建了 4 个任务,其中Factory.StartNew(),在每个任务中给出了开始位置和结束位置,任务将下载这些文件,然后它将以 byte[] 形式返回,一切都很顺利,任务工作正常,但在某些时候,执行冻结了,就这样,程序停止了,没有其他事情发生。
并行函数的实现:

static void DownloadPartsParallel()
    {

        string uriPath = "http://mschnlnine.vo.llnwd.net/d1/pdc08/PPTX/BB01.pptx";
        Uri uri = new Uri(uriPath);
        long l = GetFileSize(uri);
        Console.WriteLine("Size={0}", l);
        int granularity = 4;
        byte[][] arr = new byte[granularity][];
        Task<byte[]>[] tasks = new Task<byte[]>[granularity];
        tasks[0] = Task<byte[]>.Factory.StartNew(() => DownloadPartOfFile(uri, 0, l / granularity));
        tasks[1] = Task<byte[]>.Factory.StartNew(() => DownloadPartOfFile(uri, l / granularity + 1, l / granularity + l / granularity));
        tasks[2] = Task<byte[]>.Factory.StartNew(() => DownloadPartOfFile(uri, l / granularity + l / granularity + 1, l / granularity + l / granularity + l / granularity));
        tasks[3] = Task<byte[]>.Factory.StartNew(() => DownloadPartOfFile(uri, l / granularity + l / granularity + l / granularity + 1, l));//(l / granularity) + (l / granularity) + (l / granularity) + (l / granularity)


        arr[0] = tasks[0].Result;
        arr[1] = tasks[1].Result;
        arr[2] = tasks[2].Result;
        arr[3] = tasks[3].Result;
        Stream localStream;
        localStream = File.Create("E:\\a\\" + Path.GetFileName(uri.LocalPath));
        for (int i = 0; i < granularity; i++)
        {

            if (i == granularity - 1)
            {
                for (int j = 0; j < arr[i].Length - 1; j++)
                {
                    localStream.WriteByte(arr[i][j]);
                }
            }
            else
                for (int j = 0; j < arr[i].Length; j++)
                {
                    localStream.WriteByte(arr[i][j]);
                }
        }
    }

DownloadPartOfFile函数实现:

public static byte[] DownloadPartOfFile(Uri fileUrl, long from, long to)
    {
        int bytesProcessed = 0;
        BinaryReader reader = null;
        WebResponse response = null;
        byte[] bytes = new byte[(to - from) + 1];

        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fileUrl);
            request.AddRange(from, to);
            request.ReadWriteTimeout = int.MaxValue;
            request.Timeout = int.MaxValue;
            if (request != null)
            {
                response = request.GetResponse();
                if (response != null)
                {
                    reader = new BinaryReader(response.GetResponseStream());
                    int bytesRead;
                    do
                    {
                        byte[] buffer = new byte[1024];
                        bytesRead = reader.Read(buffer, 0, buffer.Length);
                        if (bytesRead == 0)
                        {
                            break;
                        }
                        Array.Resize<byte>(ref buffer, bytesRead);
                        buffer.CopyTo(bytes, bytesProcessed);
                        bytesProcessed += bytesRead;
                        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ",Downloading" + bytesProcessed);
                    } while (bytesRead > 0);
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            if (response != null) response.Close();
            if (reader != null) reader.Close();
        }

        return bytes;
    }

我尝试通过设置int.MaxValue读取超时、写入读取超时、写入超时来解决这个问题,这就是程序冻结的原因,如果我不这样做,在函数DownloadPartsParallel中就会出现超时异常
那么有没有解决方案,或者任何其他可能有帮助的建议,谢谢。


我会用HttpClient.SendAsync http://msdn.microsoft.com/en-us/library/hh138176(v=vs.110).aspx而不是WebRequest (see “HttpClient 来了!” http://blogs.msdn.com/b/henrikn/archive/2012/02/11/httpclient-is-here.aspx).

我不会使用任何额外的线程。 The HttpClient.SendAsyncAPI 本质上是异步的并返回一个可等待的Task<>,无需将其卸载到池线程Task.Run/Task.TaskFactory.StartNew (see this https://stackoverflow.com/q/21690385/1768303进行详细讨论)。

我还会限制并行下载的数量SemaphoreSlim.WaitAsync()。以下是我对控制台应用程序的看法(未经广泛测试):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Console_21737681
{
    class Program
    {
        const int MAX_PARALLEL = 4; // max parallel downloads
        const int CHUNK_SIZE = 2048; // size of a single chunk

        // a chunk of downloaded data
        class Chunk
        {
            public long Start { get; set; }
            public int Length { get; set; }
            public byte[] Data { get; set; }
        };

        // throttle downloads
        SemaphoreSlim _throttleSemaphore = new SemaphoreSlim(MAX_PARALLEL);

        // get a chunk
        async Task<Chunk> GetChunk(HttpClient client, long start, int length, string url)
        {
            await _throttleSemaphore.WaitAsync();
            try
            {
                using (var request = new HttpRequestMessage(HttpMethod.Get, url))
                {
                    request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(start, start + length - 1);
                    using (var response = await client.SendAsync(request))
                    {
                        var data = await response.Content.ReadAsByteArrayAsync();
                        return new Chunk { Start = start, Length = length/*, Data = data*/ };
                    }
                }
            }
            finally
            {
                _throttleSemaphore.Release();
            }
        }

        // download the URL in parallel by chunks
        async Task<Chunk[]> DownloadAsync(string url)
        {
            using (var client = new HttpClient())
            {
                var request = new HttpRequestMessage(HttpMethod.Head, url);
                var response = await client.SendAsync(request);
                var contentLength = response.Content.Headers.ContentLength;

                if (!contentLength.HasValue)
                    throw new InvalidOperationException("ContentLength");

                var numOfChunks = (int)((contentLength.Value + CHUNK_SIZE - 1) / CHUNK_SIZE);

                var tasks = Enumerable.Range(0, numOfChunks).Select(i =>
                {
                    // start a new chunk
                    long start = i * CHUNK_SIZE;
                    var length = (int)Math.Min(CHUNK_SIZE, contentLength.Value - start);
                    return GetChunk(client, start, length, url);
                }).ToList();

                await Task.WhenAll(tasks);

                // the order of chunks is random
                return tasks.Select(task => task.Result).ToArray();
            }
        }

        static void Main(string[] args)
        {
            var program = new Program();
            var chunks = program.DownloadAsync("http://flaglane.com/download/australian-flag/australian-flag-large.png").Result;

            Console.WriteLine("Chunks: " + chunks.Count());
            Console.ReadLine();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 HttpWebRequest 获得文件并行 的相关文章

  • 如何在MVVM中管理多个窗口

    我知道有几个与此类似的问题 但我还没有找到明确的答案 我正在尝试深入研究 MVVM 并尽可能保持纯粹 但不确定如何在坚持模式的同时启动 关闭窗口 我最初的想法是向 ViewModel 发送数据绑定命令 触发代码来启动一个新视图 然后通过 X
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • ASP.NET Core Serilog 未将属性推送到其自定义列

    我有这个设置appsettings json对于我的 Serilog 安装 Serilog MinimumLevel Information Enrich LogUserName Override Microsoft Critical Wr
  • UML类图:抽象方法和属性是这样写的吗?

    当我第一次为一个小型 C 项目创建 uml 类图时 我在属性方面遇到了一些麻烦 最后我只是将属性添加为变量 lt
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 如何忽略“有符号和无符号整数表达式之间的比较”?

    谁能告诉我必须使用哪个标志才能使 gcc 忽略 有符号和无符号整数表达式之间的比较 警告消息 gcc Wno sign compare 但你确实应该修复它警告你的比较
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 将布尔参数传递给 SQL Server 存储过程

    我早些时候问过这个问题 我以为我找到了问题所在 但我没有 我在将布尔参数传递给存储过程时遇到问题 这是我的 C 代码 public bool upload false protected void showDate object sende
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • C++ 复制初始化和直接初始化,奇怪的情况

    在继续阅读本文之前 请阅读在 C 中 复制初始化和直接初始化之间有区别吗 https stackoverflow com questions 1051379 is there a difference in c between copy i
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐

  • 位计数法

    谁能解释一下这个比特计数方法 public static int bitCount int i Hacker s Delight Figure 5 2 i i gt gt 1 0x55555555 i i 0x33333333 i gt g
  • 在 Windows 资源管理器中右键单击使用 VSCode 打开,没有重新打开以前的文件

    描述 当我使用右键菜单中的 使用 VS Code 打开 从 Windows 资源管理器中打开选定的文件时 VSCode 仅打开我选择的文件 它没有像sublime那样重新打开以前的文件 有什么办法可以改变这种行为吗 已经设置 window
  • Ruby on Rails - params 是方法还是哈希?

    所以 我正在尝试入门Ruby on Rails 指南部分here http guides rubyonrails org getting started html 我不明白line http guides rubyonrails org g
  • web.config IIS 中的 PHP(或其他)CGI 配置

    我最近开发了一个 Web 应用程序的安装程序 是的 带有安装程序的 Web 应用程序 使用维克斯工具套装 http wixtoolset org 该向导引导用户获取站点安装所需的所有基本信息 如下所示 在安装结束时使用自定义操作 我使用动态
  • 如何捕获实体数据源异常

    我有一个绑定到实体数据源的 gridview 我使用工具箱中的 asp net 控件拖放并使用实体数据模型创建了它 我在代码隐藏中几乎没有输入 出于测试目的 我编辑了网格视图并添加了无效的数据 然后我单击更新以引发异常 所以我的问题是我想尝
  • 如何将正常的 for 循环复制到 *ngFor

    rating 4 for i 0 i lt rating i print statement 如何使用 ngFor 在角度 6 中复制相同的 for 循环 循环应根据评级值运行 如果是 2 则应运行 2 次 我想你正在寻找这种解决方案 只需
  • 使变量最后出现在调用堆栈中

    我有一个包含一些字段的类 我需要按值比较此类的实例 所以我定义了GetHashCode and Equals因此 因为该类允许循环引用 所以我需要一种机制来避免无限递归 更详细的解释请参见值等于和循环引用 如何解决无限递归 https st
  • 使用pom文件从目标目录中删除或删除资源文件

    我在 pom xml 中有两个配置文件 并且有一些资源文件已添加到目标资源目录中 project build outputDirectory resources在执行第一个配置文件期间 我需要做的是在执行第二个配置文件期间删除这些资源文件
  • 为什么 isEmoji 实例属性对数字返回 true?

    Problem Why isEmoji实例属性对于数字返回 true 检查下面的示例 let scalars Unicode Scalar 1 for s in scalars print s gt s properties isEmoji
  • Flutter 如何只给容器边框底部

    在 Flutter 中如何仅设置底部边框 如下图所示 我有一个带有文本的容器 从底部显示红色边框 请指导如何仅从底部设置边框 Use Border与bottom争论 Container decoration BoxDecoration bo
  • 在 v-for 循环内选择 vue 2 中的特定元素

    请看代码 div div v if msg last sender click prevent loadMsg msg gt tr some html tr div loadMsg obj obj isActive obj isActive
  • Thread#run 和 Thread#wakeup 之间的区别?

    在 Ruby 中 有什么区别线程 运行 http www ruby doc org core 1 9 3 Thread html method i run and 主题 wakup http www ruby doc org core 1
  • 从 ReactNative-DatePickerAndroid 获取选定日期

    我正在关注React Native DatePicker Android 文档 https facebook github io react native docs datepickerandroid html 对于 DatePickerI
  • Python中的运算符重载:处理不同类型和顺序的参数[重复]

    这个问题在这里已经有答案了 我有一个简单的类 可以帮助对向量 即数字列表 进行数学运算 我的Vector可以乘以其他实例Vector or标量 float or int 在其他更强类型的语言中 我将创建一种方法来将两个相乘vectors 和
  • 具有条件更新的 DynamoDBContext

    在我的应用程序中 我使用亚马逊对象持久性模型并使用 DynamoDBContext 进行操作 CURD 和执行查询 我需要知道如何使用 DynamoDBContext 进行条件更新 并且它应该是异步的 我知道使用亚马逊低级 API 的方法
  • 给定 RNG 算法和一系列数字,是否可以确定哪个种子会产生该系列?

    代码是用 Objective C 写的 但即使你不了解 Objective C 如果你仔细看一下它应该是可以理解的 基本上它是一个 RNG 对象 你实例化一个新实例 如果需要的话设置种子并开始抓取随机数 那么是否可以回溯给定的一系列数字来确
  • css & html:隐藏边框的一角[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有以下用户界面 我只想隐藏三种颜色的 div 的一角 它应该看起来像这样 任何人都可以知道如何隐藏 div 边框的角 这是我要求的代
  • 错误 2003 (HY000):无法连接到 AWS RDS 上的 MySQL 服务器

    我创建了一个具有 主机名的外部用户以允许远程访问 将本地 MySQL 连接到远程 AWS RDS 时出现以下错误 错误 2003 HY000 无法连接到 instance cvxqy8tbi2bk us east 1 rds amazona
  • Android XML 解析省略“&”

    问题又是 虽然我在代码中成功实现了 SAX 解析器 但它的行为很奇怪 它只是跳过 之后的条目并转到下一个条目 只是想知道这是否是 SAX 解析器的典型工作方式还是我错误地实现了它 我已经实现了 org xml sax ContentHand
  • 如何使用 HttpWebRequest 获得文件并行

    我正在尝试制作一个像 IDM 这样的程序 它可以同时下载文件的部分内容 我用来实现此目的的工具是 C Net4 5 中的 TPL但是我在使用的时候遇到了问题Tasks使操作并行 序列功能运行良好 并且正在正确下载文件 使用任务的并行函数一直