如何防止应用程序冻结,同时检查大量 PDF 文件?

How to prevent the application from freezing, while checking a lot of PDF files?

我尝试创建一个检查大量 PDF 的程序。它可以从网络驱动器完成,只需几分钟。应用程序在此过程中全部冻结,我想避免这种情况。

我搜索了很多帖子和视频,但都没有在我的程序中实现它。我尝试了这段代码来理解它是如何工作的,但它也失败了...

async private void button1_Click(object sender, EventArgs e)
{
    rtbx.AppendText($"Processing...\n");

    // This webswite takes 1-2s to be loaded
    await HeavyWork(@"https://aion.plaync.com/");

    rtbx.AppendText($"End.\n");
}

public Task HeavyWork(string url)
{
    List<string> lesinfos = new List<string>();

    while (checkBox1.Checked == false)
    {
        using (WebClient web1 = new WebClient())
        {
            lesinfos.Add(web1.DownloadString(url));
        }
        rtbx.AppendText($"{lesinfos.Count}\n");
        this.Refresh();
    }

    rtbx.AppendText($"Done !\n");
    return Task.CompletedTask;
}

当我点击按钮时,我永远无法点击复选框,UI 也从不响应。

尝试将 DownloadStringTaskAsync(...) 与 `await 一起使用(参见下面的示例)。

public async Task HeavyWork(string url)
{
    List<string> lesinfos = new List<string>();

    while (checkBox1.Checked == false)
    {
        using (WebClient web1 = new WebClient())
        {
            var content = await web1.DownloadStringTaskAsync(url);
            lesinfos.Add(content);
        }

        rtbx.AppendText($"{lesinfos.Count}\n");
        this.Refresh();
    }

    rtbx.AppendText($"Done !\n");
}

注意:WebClient 被认为已过时,现在 recommended 使用 HttpClient

考虑到您被迫使用同步 API,您可以通过将阻塞调用卸载到 ThreadPool 线程来保持 UI 响应。用于此目的的工具是 Task.Run method. This method is specifically designed for offloading work to the ThreadPool。以下是如何使用它:

public async Task HeavyWork(string url)
{
    List<string> lesinfos = new List<string>();
    using (WebClient web1 = new WebClient())
    {
        while (checkBox1.Checked == false)
        {
            string result = await Task.Run(() => web1.DownloadString(url));
            lesinfos.Add(result);
        }
        rtbx.AppendText($"{lesinfos.Count}\n");
        this.Refresh();
    }
    rtbx.AppendText($"Done !\n");
}

注意 HeavyWork 方法签名中的 async 关键字。请注意 Task.Run 调用之前的 await。请注意末尾缺少 return Task.CompletedTask 行。

如果您不熟悉 async/await 技术,这里有一个入门教程:Asynchronous programming with async and await