.NET Framework 和 .NET Core 之间的线程池差异,线程池饥饿

     2023-04-12     200

关键词:

【中文标题】.NET Framework 和 .NET Core 之间的线程池差异,线程池饥饿【英文标题】:Thread pool differences between .NET Framework and .NET Core, Thread Pool starvation 【发布时间】:2021-02-20 16:26:07 【问题描述】:

尝试将工作代码从 .Net Framework 4.6.1 传递到 .Net Core 3.1 时,我偶然发现了一个意外行为

这是对代码的简化:

static  void Main(string[] args)

    for (int i = 0; i < 20; i++)
    
        ThreadPool.QueueUserWorkItem(o =>
        
            Console.Write($"In, ");
            RestClient restClient = new RestClient($"http://google.com");
            RestRequest restRequest = new RestRequest();
            var response = restClient.Get(restRequest);

            Console.Write($"Out, ");
        );
    

    Console.ReadLine();

控制台上的预期输出是“In”列表,然后是混合的“In”和“Out”,最后是一些“Out”,这是多线程工作的结果。这在 .Net Framework 上按预期工作。 像这样的:

In, In, In, In, In, In, In, In, In, In, In, In, In, In, In, Out, In, Out,
In, Out, In, Out, In, Out, In, Out, Out, Out, Out, Out, Out, Out, Out,
Out, Out, Out, Out, Out, Out, Out,

但是当在 .Net Core 3.1(同一台机器)上运行完全相同的代码时,看起来我们只有在所有“in”线程完成后才返回写入“out”行(我测试了这个20).

In, In, In, In, In, In, In, In, In, In, In, In, In, In, In, In, In, In,
In, In, Out, Out, Out, Out, Out, Out, Out, Out, Out, Out, Out, Out, Out,
Out, Out, Out, Out, Out, Out, Out,

意味着进程处于饥饿状态,如果添加到线程池的工作项的数量是无限的(例如取决于 API),则永远不会处理 HTTP 响应。

我认为这是因为 ThreadPool 算法选择下一个线程来处理 this is a nice article on the subject 的方式

我不明白为什么它不会在 .Net Framework 上发生,如果我可以让它在 .Net Core 上以某种方式工作。

附:我并不是想避免与 TPL 合作,我只是想弄清楚这一点。

有什么建议吗?

【问题讨论】:

如果您将 REST 调用替换为像 Thread.Sleep(500) 这样的简单阻塞调用,是否也会发生这种情况?我要求排除差异与RestClient 而不是ThreadPool 相关的可能性。 “意味着这个过程中存在饥饿”请解释你是如何得出这个结论的。 @TheodorZoulias 我用睡眠进行了测试,然后它作为例外执行。但是,使用 rest 客户端或常规 httprequest - 在 .net core 8(num cores)上,theads 开始执行,然后池添加 1 个线程,直到 20,并且只有在请求开始完成之后。我不明白为什么会在这种情况下发生这种情况。没有等待,因此与排队的延续无关。 我不太确定这是怎么回事。但是说请求自然需要大约 1 秒。然后我希望启动 8 个线程,然后池每秒左右添加几个新线程,然后请求应该开始完成,因为您的请求是同步的并且它已经在线程池线程上执行 - 它没有'不需要池中的 new 线程来完成请求。当 requset 是异步的并且它需要池中的 new 线程在异步之后执行继续时,就会发生文章中描述的那种饥饿。 @NetanelSwartz 你的问题很有趣。 ThreadPool 的实现可能在 .NET Framework 和 .NET Core 之间发生了变化。我找不到任何关于它的信息。 【参考方案1】:

[已编辑]这是我发现的

.NET Core 和 .NET Framework 的区别在于HttpWebRequest.GetResponse() 的实现。在 .NET Framework 中,它使用 Thread.SpinWait(1),而在 .NET Core 中,它使用 SendRequest().GetAwaiter().GetResult() - 本质上是调用异步实现并对其执行 Wait()。

异步方法调用依赖TaskScheduler 来执行延续。 TaskScheduler 依赖于 ThreadPool。

通常,线程池以 minThreads = # cores 开始。然后它使用某种算法慢慢地增加线程数,直到达到 maxThreads。

代码立即将 20 个阻塞作业发布到线程池。延续作业排在它们之后。线程池会慢慢增加线程数以适应下载作业,然后才会添加一个线程来处理第一个 Continuation 作业。

另一个有趣的转折是,如果您将最小和最大线程都设置为相同的低值并​​运行代码,它就会死锁。那是因为 Continuation 永远不会收到要执行的线程。有关死锁的更多信息here。

有多种方法可以解决这个问题

    避免混合同步和异步代码。一路异步(如果可以的话) 使用ThreadPool.SetMinThreads 以启动足够数量的线程。您至少需要线程数作为预期的并发下载作业数。 在示例代码中,如果您在发布下载作业之间添加 10 到 50 毫秒的延迟,则后续作业有机会在其间安排。

(这个问题使用了一个叫做 RestClient 的东西,它可能在后台使用 HttpClient 或 HttpWebRequest。下面的代码使用 HttpWebRequest)

private static void Main(string[] args)

    //ThreadPool.SetMinThreads(4, 4);
    //ThreadPool.SetMaxThreads(4, 4);
    for (var i = 0; i < 20; i++)
        ThreadPool.QueueUserWorkItem(o =>
        
            Console.Write("In, ");

            var r = (HttpWebRequest) WebRequest.Create("http://google.com");
            r.GetResponse();
            //Try this in .Net Framework and get the same result in as in .NET Core.
            //That's because in .NET Core r.GetResponse() essentially does r.GetResponseAsync().Wait()
            //r.GetResponseAsync().Wait();  

            Console.Write("Out, ");
        );

    Console.ReadLine();

【讨论】:

但是没有GetAsync().Wait(...) 有问题,也没有使用HttpClient。我对HttpWebRequest 进行了同样的尝试(它确实有同步的Get 方法) 原题使用RestClient。不确定它到底是什么,但很可能它在后台使用了 HttpClient。下面是HttpWebRequest.GetResponse的实现:return SendRequest().GetAwaiter().GetResult(); 仍然不知道为什么它在 .NET Framework 和 .NET Core 之间的工作方式不同。 编辑答案以反映更好的发现并回答 .NET FW 和 .NET CORE 之间的区别【参考方案2】:

问题似乎在于 ThreadPool “旨在最大化吞吐量,而不是最小化延迟”。

我认为以下文章为理解这种行为提供了一个很好的起点: Article

【讨论】:

RijndaelManaged .NET Framework 和 .NET Core 的区别

】RijndaelManaged.NETFramework和.NETCore的区别【英文标题】:RijndaelManageddifferencein.NETFrameworkand.NETCore【发布时间】:2021-11-1712:33:51【问题描述】:我在两个项目中使用完全相同的类来加密/解密字符串,一个项目针对.NETFramework4.8和第二... 查看详情

.Net Full framework 和 K runtime 使用的 .Net Core Framework 4.5 的区别?

】.NetFullframework和Kruntime使用的.NetCoreFramework4.5的区别?【英文标题】:Differencesbetween.NetFullframeworkandthe.NetCoreFramework4.5usedbyKruntime?【发布时间】:2014-08-1117:18:03【问题描述】:我看过介绍ASP.NETvNext的视频,并一直在关注最近发布... 查看详情

.Net Framework 3.5 和 .Net Framework 3.5 SP1 有相同的版本号吗?

】.NetFramework3.5和.NetFramework3.5SP1有相同的版本号吗?【英文标题】:.NetFramework3.5and.NetFramework3.5SP1havesameversionnumber?【发布时间】:2019-05-1012:42:09【问题描述】:我听说我可以从HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NETFrameworkSetup\\NDP\\v3. 查看详情

.NET Framework 开发包和.net core 有啥区别? [复制]

】.NETFramework开发包和.netcore有啥区别?[复制]【英文标题】:whatisthedifferencebetween.NETFrameworkDevelopPackand.netcore?[duplicate].NETFramework开发包和.netcore有什么区别?[复制]【发布时间】:2018-05-0903:27:08【问题描述】:我已经导航到https://ww... 查看详情

在 .NET Framework 和 .NET Core 之间自动传递和拉取 JSON 数据

】在.NETFramework和.NETCore之间自动传递和拉取JSON数据【英文标题】:AutomaticallyPassingandPullingJSONdatabetween.NETFrameworkand.NETCore【发布时间】:2019-08-0819:03:03【问题描述】:我是计算机科学的新手(所以希望我使用正确的词并提供正确... 查看详情

.NET Framework 和 .NET Core 之间的线程池差异,线程池饥饿

】.NETFramework和.NETCore之间的线程池差异,线程池饥饿【英文标题】:Threadpooldifferencesbetween.NETFrameworkand.NETCore,ThreadPoolstarvation【发布时间】:2021-02-2016:26:07【问题描述】:尝试将工作代码从.NetFramework4.6.1传递到.NetCore3.1时,我偶然... 查看详情

用于 .Net Framework 和 .Net Core 的 TeamCity 和 SonarQube 依赖项检查器

】用于.NetFramework和.NetCore的TeamCity和SonarQube依赖项检查器【英文标题】:DependencyCheckerwithTeamCityandSonarQubefor.NetFrameworkand.NetCore【发布时间】:2020-06-1915:02:31【问题描述】:我在将依赖检查器输出从构建代理发送到SonarQube服务器时... 查看详情

Grid 控件的 RenderSize 在 Windows 10 [.NET Framework 4.6.2] 和 Windows 7[.NET Framework 4] 中有所不同

】Grid控件的RenderSize在Windows10[.NETFramework4.6.2]和Windows7[.NETFramework4]中有所不同【英文标题】:RenderSizeofGridcontrolhavedifferenceinWindows10[.NETFramework4.6.2]andWindows7[.NETFramework4]【发布时间】:2018-12-1311:52:46【问题描述】:我有一个自定义组 查看详情

.Net Framework 和 .Net Core 在同一个解决方案中

】.NetFramework和.NetCore在同一个解决方案中【英文标题】:.NetFrameworkand.NetCoreinsamesolution【发布时间】:2016-10-1013:29:55【问题描述】:我有一个面向.NETFramework的应用程序,现在我需要在.NETCore中开发一个库。我计划将这两个项目放... 查看详情

更改 WCF 服务以与 .NET Framework 和 .NET Core 调用者兼容

】更改WCF服务以与.NETFramework和.NETCore调用者兼容【英文标题】:AlteraWCFServiceforCompatibilitywithboth.NETFramework&.NETCoreCallers【发布时间】:2019-10-2102:15:06【问题描述】:TL;DR我有一个作为Windows服务托管的现有WCF服务,我想对其进行... 查看详情

Entity Framework 和 .NET 的一对一关系

】EntityFramework和.NET的一对一关系【英文标题】:One-to-onerelashionshipEntityFrameworkand.NET【发布时间】:2021-09-2509:59:00【问题描述】:我首先使用代码在我的类之间创建关系。集成发生在MySql中,但是,在迁移后,当我检查我的工作台... 查看详情

Java 是不是有类似于 .Net Framework 和 Entity Framework 的迁移工具

】Java是不是有类似于.NetFramework和EntityFramework的迁移工具【英文标题】:DoesJavahaveamigrationstoolsimlarto.NetFrameworkandEntityFrameworkJava是否有类似于.NetFramework和EntityFramework的迁移工具【发布时间】:2020-11-1913:33:36【问题描述】:我最近... 查看详情

如何检测安装了哪些 .NET Framework 版本和服务包?

】如何检测安装了哪些.NETFramework版本和服务包?【英文标题】:HowdoIdetectwhat.NETFrameworkversionsandservicepacksareinstalled?【发布时间】:2010-09-1623:28:36【问题描述】:here提出了类似的问题,但它是特定于.NET3.5的。具体来说,我正在寻... 查看详情

需要(RPC + C# .Net + Framework 4.0)示例 [关闭]

】需要(RPC+C#.Net+Framework4.0)示例[关闭]【英文标题】:Need(RPC+C#.Net+Framework4.0)Samples[closed]【发布时间】:2011-11-1108:27:25【问题描述】:我想要一些C#.Net和Framework4.0中远程过程调用的示例。我已经搜索了很多谷歌。但我找不到RPC概... 查看详情

我可以在一个 IIS 站点中部署 .Net Framework 4.8.2 和 .Net 5 应用程序吗?

】我可以在一个IIS站点中部署.NetFramework4.8.2和.Net5应用程序吗?【英文标题】:CanIdeploya.NetFramework4.8.2anda.Net5appsinoneIISsite?【发布时间】:2021-12-1817:48:08【问题描述】:我有2个应用程序,一个是Asp.NetMVC(在.Net框架4.8.2中),另一... 查看详情

Cosmos 的 .NET 5 和 Entity Framework Core (5.0.1) 迁移问题

】Cosmos的.NET5和EntityFrameworkCore(5.0.1)迁移问题【英文标题】:.NET5andEntityFrameworkCore(5.0.1)migrationissuewithCosmos【发布时间】:2021-04-0708:37:05【问题描述】:我有一个控制台应用程序(.NET5),它使用EntityFrameworkCore5.0.1来处理AzureCosmos数据... 查看详情

ADO.NET Entity Framework 和 NHibernate - 何时使用其中之一

】ADO.NETEntityFramework和NHibernate-何时使用其中之一【英文标题】:ADO.NETEntityFrameworkandNHibernate-whentouseoneovertheother【发布时间】:2009-04-0821:42:26【问题描述】:我在Microsoft.NET商店工作,可以使用NHibernate或ADO.NETEF。关于何时应该选择... 查看详情

使用 .NET Core(.NET Standard 1.4 和 .NET Framework 4.6.1)对 System.Net.Http 使用 await/async 时出现错误?

】使用.NETCore(.NETStandard1.4和.NETFramework4.6.1)对System.Net.Http使用await/async时出现错误?【英文标题】:Bugwhenusingawait/asyncforSystem.Net.Httpwith.NETCore(.NETStandard1.4and.NETFramework4.6.1)?【发布时间】:2017-01-1715:23:08【问题描述】:前景:我正... 查看详情