簡體   English   中英

線程池中的排隊任務正在退出,沒有被釋放回池中

[英]Queued tasks in thread pool are exiting, not being released back into pool

我正在編寫一個 C# Blazor MAUI 應用程序並嘗試執行一些自動化的后台任務。 每 30 秒,我的應用程序會掃描配置以在一組用戶定義的服務器上執行連接測試。

public static bool CanConnect(string host, int port, TimeSpan timeout) {
    try {
        using (var client = new TcpClient()) {
            var result = client.BeginConnect(host, port, null, null);
            var success = result.AsyncWaitHandle.WaitOne(timeout);
            client.EndConnect(result);
            System.Diagnostics.Debug.Print($"Success! {host}:{port}");
            return success;
        }
    } catch {
        System.Diagnostics.Debug.Print($"Failed connecting to {host}:{port}");
        return false;
    }
}

當我的調度程序開始對這些任務進行排隊時,我注意到 GUI 上有一個非常輕微(但很明顯)的小問題。

clusters.AsParallel()
        .ForAll(item => item.Status = ClusterIsAccessible(item) ? Cluster.ConnectionStatus.Online : Cluster.ConnectionStatus.Offline);

我相信打嗝是創建線程的結果。 我注意到當作業完成時,用於掃描連接的線程將在 20-25 秒后退出/超時。

The thread 0x225c has exited with code 0 (0x0).
The thread 0x4d2c has exited with code 0 (0x0).
The thread 0x7c28 has exited with code 0 (0x0).
The thread 0x6724 has exited with code 0 (0x0).
The thread 0x822c has exited with code 0 (0x0).
The thread 0x849c has exited with code 0 (0x0).
The thread 0x5a24 has exited with code 0 (0x0).
The thread 0x86ac has exited with code 0 (0x0).
The thread 0x8840 has exited with code 0 (0x0).
The thread 0x22f8 has exited with code 0 (0x0).
The thread 0x74e0 has exited with code 0 (0x0).
The thread 0x7550 has exited with code 0 (0x0).
The thread 0x8b80 has exited with code 0 (0x0).
The thread 0x4d48 has exited with code 0 (0x0).
The thread 0x14a8 has exited with code 0 (0x0).
The thread 0x5ed0 has exited with code 0 (0x0).

我的想法是 LINQ 沒有使用線程池,而是為每個任務初始化新線程。

為了嘗試將作業強制到現有的 C# 線程池上,我重寫了迭代邏輯以使用ThreadPool::QueueUserWorkItem(...)但這也導致線程退出並在創建線程時出現輕微的打嗝。

clusters.ForEach((item) => ThreadPool.QueueUserWorkItem(state => {
    item.Status = ClusterIsAccessible(item) ? Cluster.ConnectionStatus.Online : Cluster.ConnectionStatus.Offline;
}));

我究竟做錯了什么? 當已經有線程等待工作時,我不想創建不必要的線程。

問題是WaitOne阻塞了一個線程池線程,這意味着在短暫等待后將創建一個新線程。 線程池將繼續創建越來越多的線程以滿足您的請求,因為每個線程都不斷被阻塞。

相反,您應該使用async await ,它允許線程池線程 go 關閉並執行其他操作,直到響應返回

public static async Task<bool> CanConnect(string host, int port, TimeSpan timeout)
{
    try
    {
        using (var cancel = new CancellationTokenSource(timeout))
        using (var client = new TcpClient())
        {
            await client.ConnectAsync(host, port, cancel.Token);
            System.Diagnostics.Debug.Print($"Success! {host}:{port}");
            return true;
        }
    }
    catch
    {
        System.Diagnostics.Debug.Print($"Failed connecting to {host}:{port}");
        return false;
    }
}

然后你不使用Parallel.ForEach而是使用Task.WaitAll來調用它

await Task.WhenAll(
    clusters.Select(async item =>
        item.Status = (await ClusterIsAccessible(item)) ? Cluster.ConnectionStatus.Online : Cluster.ConnectionStatus.Offline)
  );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM