C# 为什么在debug-build-run中线程池以2个线程开始?

问题描述 投票:0回答:1

代码:

public class Test
{
    public static void Main()
    {
        int threadCount = ThreadPool.ThreadCount;
        Console.WriteLine($"thread count : {threadCount}");
        
        ThreadPool.SetMinThreads(1, 2);
        Console.WriteLine(ThreadPool.SetMaxThreads(1, 2));
        
        List<Task> tlist = new();
        
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine($"repeat {i}");
            
            tlist.Add(Task.Run(() =>
            {
                threadCount = ThreadPool.ThreadCount;
                Console.WriteLine($"thread count : {threadCount}");
                return FuncAsync();
            }));
            Console.WriteLine($"repeat end {i}");
        }

        Task.WaitAll(tlist.ToArray());
    }

    public static async Task FuncAsync()
    {
        Console.WriteLine("FuncAsync");
    }
}

此代码仅在使用“发布”构建“运行”时才起作用

调试 跑步
调试构建 工作 不工作
发布构建 工作 工作

enter image description here

首先,对不起我的英语能力......

我想知道当线程池的最大容量为1时,异步方法如何工作。 但我遇到了一些意想不到的错误。

当我尝试使用调试构建运行时,线程池开始时已经填充了 2 个线程。 enter image description here

所以,线程池中没有负担得起的线程,那就不行了。就这样无限地停下来…… enter image description here

但是一开始就不会出现这种情况

  1. 使用调试构建进行调试
  2. 使用发布版本进行调试
  3. 使用发布版本运行

有人知道为什么会出现这种情况吗?

c# debugging asynchronous threadpool
1个回答
2
投票

我没有安装 Rider,但 VS 中也发生了同样的事情,所以我要回答这个问题。我认为 Rider 也会发生类似的情况。

在 VS 中,我们可以启动进程,然后执行 Debug -> Attach to Process... 将调试器附加到我们启动的进程。点击“Break”,然后查看“线程”窗口,我们会看到:

我们可以看到主线程(卡在

Task.WaitAll)
上)和工作线程。如果我们双击工作线程并查看“调用堆栈”窗口,我们会看到:

您可以看到有人打电话给

Task.Run
。值得注意的是,这不是您的代码。正在执行但不在运行时中的代码位是:

Microsoft.Extensions.DotNetDeltaApplier.dll!StartupHook.Initialize.AnonymousMethod__0() Unknown
Microsoft.Extensions.DotNetDeltaApplier.dll!StartupHook.ConnectToPipeAndSendCapabilitiesAsync()
Microsoft.Extensions.DotNetDeltaApplier.dll!Microsoft.Extensions.HotReload.ClientInitializationPayload.Write(System.IO.Stream stream)

什么是

DotNetDeltaApplier
?去谷歌!来自这个答案

VS 2022 将 dll 加载到您的进程中:Microsoft.VisualStudio.Debugger.Runtime.NetCoreApp.dll、Microsoft.Extensions.DotNetDeltaApplier.dll 等。如果您禁用热重载(项目属性/调试),它应该可以工作(这可能是使用 COM 在应用程序和重新加载之间进行通信)

(我们可以看到它实际上使用的是命名管道而不是 COM,但这并不重要。)

因此 VS 已将额外的 DLL 加载到我们的进程中(使用启动挂钩)以支持热重载(在其中更改源代码并将这些更改修补到正在运行的可执行文件中)。该额外的 DLL 已占用并阻塞了 ThreadPool 线程,这意味着 ThreadPool 中没有剩余线程来运行您的

Task.Run

事实上,如果您直接在文件系统上找到并运行 exe(而不是从 VS 启动),它就会运行完成。

© www.soinside.com 2019 - 2024. All rights reserved.