英文:
DownloadFileCompleted being executed before the file has finished downloading
问题
DownloadFileCompleted
在文件下载完成之前运行,导致文件大小为0字节,计数器错误。
foreach (var img in image_list)
{
await Task.Run(() => DownloadFile(img));
}
private async Task DownloadFile(JToken file)
{
using (WebClient client = new WebClient())
{
client.DownloadFileCompleted += DownloadFileCompleted(file["name"]);
client.DownloadFileAsync(new Uri(file["url"]));
}
}
private AsyncCompletedEventHandler DownloadFileCompleted(string nome)
{
total_download++;
label1.Text = total_download;
}
我想并行下载多个文件,而在文件完成下载后递增计数,但计数在下载完成之前被递增(0字节的图像被计为完整下载)。
英文:
DownloadFileCompleted
is running before the file has finished downloading resulting in files with 0 bytes and a wrong counter.
foreach (var img in image_list)
{
await Task.Run(() => DownloadFile(img));
}
private async Task DownloadFile(JToken file) {
using (WebClient client = new WebClient()) {
client.DownloadFileCompleted += DownloadFileCompleted(file["name"]);
client.DownloadFileAsync(new Uri(file["url"]);
}
}
private AsyncCompletedEventHandler DownloadFileCompleted(string nome) {
total_download++;
label1.Text = total_download;
}
I would like to download several files in parallel and as the file finishes downloading, a count is incremented but the count is being incremented before the download is completed (images with 0 bytes are being counted as a complete download).
答案1
得分: 0
我不建议在IO操作中使用多线程方法,因为线程会等待(更准确地说,它在应用程序线程池中不必要地保持),直到IO操作完成,同时什么都不做,最终导致资源使用不合理。
如果你想让你当前的代码工作,可以通过添加async
和await
来修复它:
foreach (var img in image_list)
{
await Task.Run(async () => await DownloadFile(img));
}
private async Task DownloadFile(JToken file) {
using (WebClient client = new WebClient()) {
client.DownloadFileCompleted += DownloadFileCompleted(file["name"]);
await client.DownloadFileTaskAsync(new Uri(url), "some save location");
}
}
private AsyncCompletedEventHandler DownloadFileCompleted(string name) {
total_download++;
label1.Text = total_download;
}
如果你想创建最优化的解决方案,我建议了解IAsyncEnumerable
,它使你能够异步迭代集合。
英文:
I don't recommend multithreading approach for IO operations, since thread waits (more precisely speaking it is unnecessarily hold in app thread pool - multithreading of IO operations results in unoptimal resource usage in the end) for IO operation to complete, doing nothing in meantime.
If you want to make your current code work though, it can be fixed by adding async
and await
:
foreach (var img in image_list)
{
await Task.Run(async () => await DownloadFile(img));
}
private async Task DownloadFile(JToken file) {
using (WebClient client = new WebClient()) {
client.DownloadFileCompleted += DownloadFileCompleted(file["name"]);
await client.DownloadFileTaskAsync(new Uri(url), "some save location");
}
}
private AsyncCompletedEventHandler DownloadFileCompleted(string nome) {
total_download++;
label1.Text = total_download;
}
If you want to create the most optimal solution, i recommend to get to know about IAsyncEnumerable
, which gives you possibility of aynschronous iterating over collection.
答案2
得分: 0
你应该只使用 HttpClient
而不是 WebClient
,并且在每个地方都使用 async
和 await
,而不是仅仅使用 Task.Run
来卸载下载。
static HttpClient _Client = new();
foreach (var img in image_list)
{
await DownloadFile(img);
total_download++;
label1.Text = total_download;
}
private async Task DownloadFile(JToken file)
{
using var stream = await _client.GetStreamAsync(file["url"]);
using var fs = File.OpenWrite(file["name"]); // 或其他路径在此处
await stream.CopyToAsync(fs);
}
英文:
You should just use HttpClient
instead of WebClient
, and use async
and await
everywhere, rather than just hacking Task.Run
to offload the download.
static HttpClient _Client = new();
foreach (var img in image_list)
{
await DownloadFile(img);
total_download++;
label1.Text = total_download;
}
private async Task DownloadFile(JToken file)
{
using var stream = await _client.GetStreamAsync(file["url"]);
using var fs = File.OpenWrite(file["name"])); // or other path here
await stream.CopyToAsync(fs);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论