DownloadFileCompleted 在文件下载完成之前被执行

huangapple go评论71阅读模式
英文:

DownloadFileCompleted being executed before the file has finished downloading

问题

DownloadFileCompleted 在文件下载完成之前运行,导致文件大小为0字节,计数器错误。

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.

Files with 0 bytes

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操作完成,同时什么都不做,最终导致资源使用不合理。

如果你想让你当前的代码工作,可以通过添加asyncawait来修复它:

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,并且在每个地方都使用 asyncawait,而不是仅仅使用 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);
}

huangapple
  • 本文由 发表于 2023年7月20日 10:12:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76726250.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定