更新
Jimi 刚刚在评论中向我指出,DownloadFileAsync 是一个事件驱动的调用,不能等待。虽然有一个 WebClient.DownloadFileTaskAsync 版本,这将是本示例中使用的合适版本,但它是一个等待调用并返回一个 Task
以异步方式将指定资源下载到本地文件
使用任务对象进行操作。
原答案
我知道我可以运行多个线程,甚至可以并行运行,但是什么是
最好的方法
是的,您可以使其并行化并控制您使用的资源。
我不太担心速度,只要它不像正确的那么慢
现在,但我不想压倒设备的资源,例如 CPU
试图加快速度
您应该能够实现这一点并很好地配置它。
好的,所以有很多方法可以做到这一点。以下是一些需要考虑的事情:
- 您有 1000 个 IO bound 任务(而不是 CPU bound 任务)
- 有了这么多文件,您需要某种并行性并能够配置并发任务的数量。
- 您将希望以
async / await 模式执行此操作,这样您就不会在 IO 完成端口上浪费系统资源或破坏 CPU
一些直接的解决方案:
请注意:还有很多其他方法。
所以Parallel.ForEach 使用线程池。此外,IO 绑定 操作会阻塞那些等待设备响应的线程并占用资源。这里的一般经验法则是
- 如果您有CPU 绑定代码,
Parallel.ForEach 是合适的;
- 虽然如果你有 IO 绑定 代码,Asynchrony 是合适的。
这种情况下,下载一个文件明明是I/O,有DownloadFileAsync版本,1000个文件要下载,所以你最好用async/await模式和对并发任务的某种类型的限制
这是一个非常基本的示例,说明如何实现这一目标:
给定
public class WorkLoad
{
public string Url {get;set;}
public string FileName {get;set;}
}
数据流示例
public async Task DoWorkLoads(List<WorkLoad> workloads)
{
var options = new ExecutionDataflowBlockOptions
{
// add pepper and salt to taste
MaxDegreeOfParallelism = 50
};
// create an action block
var block = new ActionBlock<WorkLoad>(MyMethodAsync, options);
// Queue them up
foreach (var workLoad in workloads)
block.Post(workLoad );
// wait for them to finish
block.Complete();
await block.Completion;
}
...
// Notice we are using the async / await pattern
public async Task MyMethodAsync(WorkLoad workLoad)
{
try
{
Console.WriteLine("Downloading: " + workLoad.Url);
await client.DownloadFileAsync(workLoad.Url, workLoad.FileName);
}
catch (Exception)
{
// probably best to add some error checking some how
}
}
总结
这种方法给你异步,也给你MaxDegreeOfParallelism,不浪费资源,让IO成为IO
免责声明,DataFlow 可能不是您想要的,但我只是想给您更多信息
免责声明 2,另外上面的代码还没有经过测试,我会认真考虑先研究这项技术,并彻底做你的尽职调查。
Loosely related demo here