Task.WaitAll は WinForms のクリック ハンドラー内で、検査自体が非同期 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 は上限付きの非同期 I/O を実行し、1 つの結果を返します。バックグラウンド スレッドからコントロールを操作しません。ShowResults と ShowCheckError はアプリケーションのメソッドです。

await の通常の継続はハンドラーが開始した UI コンテキストに戻るため、ShowResults でコントロールを更新できます。別スレッドで明示的に実行されるコードは、サポートされている WinForms の仕組みでコントロール アクセスをマーシャリングする必要があります。

無料プロキシ一覧 から入力アドレスを取得できます。渡すのは CheckProxyAsync が実装するプロトコルだけにしてください。8 はあくまで例の予算です。次のバッチは現在のバッチで最も遅い検査を待つため、一部のスループットを上限付きのタスク生成と引き換えます。各検査の期限とキャンセルは CheckProxyAsync の中に保ってください。バッチを待つだけでは、無制限のネットワーク操作を終わらせることはできません。

関連記事