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 + "%)"
            );
    }
}
Другие вопросы по тегам