在 WinForms 单击处理程序中使用 Task.WaitAll 会阻塞窗口,即使检查本身使用异步 HTTP 也是如此。UI 线程无法处理消息,而被捕获的后续代码可能仍需要那个被阻塞的线程。

对于 .NET 6 或更高版本,改为等待一个限量批次:

private async void checkButton_Click(object sender, EventArgs e)
{
    checkButton.Enabled = false;
    try
    {
        var entries = proxyList.Lines
            .Where(line => !string.IsNullOrWhiteSpace(line));
        foreach (var batch in entries.Chunk(8))
        {
            var results = await Task.WhenAll(batch.Select(CheckProxyAsync));
            ShowResults(results);
        }
    }
    catch (Exception error)
    {
        ShowCheckError(error);
    }
    finally
    {
        checkButton.Enabled = true;
    }
}

这适用于已存在且可用的 System.Linq 和 System.Threading.Tasks 的窗体。CheckProxyAsync 执行有界的异步输入输出并返回一个结果;它不会从后台线程操作控件。ShowResults 和 ShowCheckError 是应用程序方法。

await 的正常后续代码会回到处理程序启动时的 UI 上下文,因此 ShowResults 可以更新控件。显式在另一个线程上运行的代码必须通过 WinForms 支持的机制来编组控件访问。

免费 proxy 列表可以提供输入地址;只传入 CheckProxyAsync 实现的协议。八是示例预算。下一批要等待当前批次中最慢的检查,用部分吞吐量换取有界的任务创建。把每次检查的超时和取消保留在 CheckProxyAsync 中;等待批次并不能让无界的网络操作结束。

相关文章