WebClient.DownloadProgressChanged: Console.WriteLine() is blocking UI thread
У меня есть следующий простой код:
private void btn_download_Click(object sender, EventArgs e){
WebClient client = new WebClient();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFileAsync(new Uri("http://.../file.zip"), "file.zip");
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e){
//Prints: "Downloaded 3mb of 61.46mb (4%)"
Console.WriteLine("Downloaded "
+ ((e.BytesReceived / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " of "
+ ((e.TotalBytesToReceive / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " (" + e.ProgressPercentage + "%)"
);
}
Why is this blocking the UI thread? Когда я заменяю Console.WriteLine()
with code to update my progress bar (not show in code), it works. The UI is responsive.
1 ответ
То, как вы это делаете, похоже на то, как MSDN показывает в своих примерах. Я тоже попробовал и получил тот же результат. Вы увидите похожее поведение при запуске чего-либо в отдельном потоке, который затем слишком быстро перезванивает в основной поток пользовательского интерфейса и обновляет его. Поток пользовательского интерфейса резервируется и эффективно зависает.
Тот DownloadProgressChanged
событие запускается очень быстро... кажется, сотни раз в секунду, это означает, что он пытается записать на консоль тоже быстро.
Вы можете ограничить частоту записи в консоль, что решит проблему (я протестировал ее, пытаясь загрузить ISO-образ 4 ГБ, и он записал в консоль, оставив отзывчивым интерфейс):
// define a class-level field variable
private int counter;
private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
counter++;
// Only print to the console once every 500 times the event fires,
// which was about once per second when I tested it
if (counter % 500 == 0)
{
//Prints: "Downloaded 3mb of 61.46mb (4%)"
Console.WriteLine("Downloaded "
+ ((e.BytesReceived / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " of "
+ ((e.TotalBytesToReceive / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " (" + e.ProgressPercentage + "%)"
);
}
}