- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我写了一个简单的基于异步的负载测试库,它还有一个控制台界面可以从命令行进行测试。
基本上,它同时运行大量请求,聚合它们,并显示摘要和简单的直方图。没有什么花哨。但是我在本地系统中运行了很多测试,所以我想确保测试工具能够使用尽可能少的资源来获得相对准确的基准测试。因此它使用带有 Begin/End 方法的纯异步来保持最少的开销。
全部完成,完全异步,它可以工作,并且不碍事(好吧,大部分)。但是正常 session 中的线程数远远超过 40。因此,对于具有 4 个硬件线程的机器来说,这是一种非常巧妙的资源浪费,考虑到本地机器也在运行正在测试的服务器。
我已经在 AsyncContext 中运行该程序,它基本上只是一个简单的排队上下文,将所有内容都放在同一个线程上。所以,所有 aync 回发都在主线程上。完美。
现在,我所要做的就是限制 ThreadPool 的最大线程数,然后看看它的性能如何。将其限制为实际核心,具有 4 个工作线程和 4 个 IOCP 线程。
Result?
Exception: "There were not enough free threads in the ThreadPool to complete the operation."
好吧,这不是一个新问题,并且在整个 Internet 上相当分散。但是,ThreadPool 的全部意义不在于您可以将事情放到池的队列中,并且只要有线程可用它就会执行吗?
事实上,该方法的名称是“Queue”UserWorkItem。并且文档恰本地说,“排队执行一个方法。当线程池线程可用时执行该方法。”
现在,如果没有足够的空闲线程可用,理想情况下,可能会减慢程序的执行速度。 IOCP 和异步任务应该只是排队,但为什么它以这样一种方式实现,它撞倒了,反而失败了?增加线程数不是解决方案,因为它被称为 ThreadPool 旨在成为队列。
Edit - Clarification:
I'm fully aware of the concept of the threadpool, and why the CLR spins up more threads. It should. I agree that it is infact the correct thing to do when there are heavy IO-bound tasks. But the point is, if you do infact restrict the threads in the ThreadPool, it is expected to queue the task for execution whenever a free thread is available, not throw an exception. The concurrency could be affected, perhaps even slowing down the outcome, but a QueueWorkUserItem is intented to Queue, not work only when a new thread is available, or fail - hence, my speculative assertion that its an implementation bug, as stated in the title.
更新 1:
与 Microsoft 支持论坛中记录的相同问题以及示例: http://support.microsoft.com/default.aspx?scid=kb;EN-US;815637
建议的解决方法,显然是增加线程数,因为它无法排队。
注意:这是在非常旧的运行时下,下面给出了在 4.5.1 运行时上重现相同问题的方法。
更新 2:
在 Mono Runtime 上运行相同的代码片段,ThreadPool 似乎没有问题。它被排队,然后被执行。该问题仅在 Microsoft CLR 下发生。
更新 3:
@Noseratio 指出无法在 .NET 4.5.1 下重现相同代码的有效问题后,下面是一段可以重现该问题的代码。为了打破在按预期排队时工作的代码,真正需要做的就是向排队的委托(delegate)添加一个真正的异步调用。
例如,仅将以下行添加到委托(delegate)的末尾应该以异常结束:
(await WebRequest.Create("http://www.google.com").GetResponseAsync()).Close();
复制代码:
这是对 MSKB 文章稍作修改的代码,在 Windows 8.1 的 .NET 4.5.1 下应该会很快失败。
(请随意更改 url 和线程限制)。
public static void Main()
{
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(2, 2);
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Queued {0}", i);
ThreadPool.QueueUserWorkItem(PoolFunc);
}
Console.ReadLine();
}
private static async void PoolFunc(object state)
{
int workerThreads, completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Console.WriteLine(
"Available: WorkerThreads: {0}, CompletionPortThreads: {1}",
workerThreads,
completionPortThreads);
Thread.Sleep(1000);
string url = "http://localhost:8080";
HttpWebRequest myHttpWebRequest;
// Creates an HttpWebRequest for the specified URL.
myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
// Sends the HttpWebRequest, and waits for a response.
Console.WriteLine("Wait for response.");
var myHttpWebResponse = await myHttpWebRequest.GetResponseAsync();
Console.WriteLine("Done.");
myHttpWebResponse.Close();
}
非常感谢任何对此行为的深入了解,这可能会为此提供推理。谢谢。
最佳答案
在您的示例代码中,不是调用 QueueUserWorkItem
引发异常,而是调用 await myHttpWebRequest.GetResponseAsync()
引发异常。如果您查看异常详细信息,您可以准确地看到是什么方法抛出了这个异常
System.InvalidOperationException was unhandled by user code
_HResult=-2146233079
_message=There were not enough free threads in the ThreadPool to complete the operation.
HResult=-2146233079
IsTransient=false
Message=There were not enough free threads in the ThreadPool to complete the operation.
Source=System
StackTrace:
at System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)
at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl(Func`3 beginMethod, Func`2 endFunction, Action`1 endAction, Object state, TaskCreationOptions creationOptions)
at System.Threading.Tasks.TaskFactory`1.FromAsync(Func`3 beginMethod, Func`2 endMethod, Object state)
at System.Net.WebRequest.<GetResponseAsync>b__8()
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at ConsoleApplication1.Program.<PoolFunc>d__0.MoveNext() in c:\Users\Justin\Source\Repos\Azure\ConsoleApplication1\ConsoleApplication1\Program.cs:line 39
InnerException:
确实,如果我们看一下 HttpWebRequest.BeginGetResponse
method我们可以看到以下内容
if (!RequestSubmitted && NclUtilities.IsThreadPoolLow())
{
// prevent new requests when low on resources
Exception exception = new InvalidOperationException(SR.GetString(SR.net_needmorethreads));
Abort(exception, AbortState.Public);
throw exception;
}
这个故事的寓意是线程池是其他代码(包括部分 .Net 框架)也使用的共享资源 - 将最大线程数设置为 2 是 Raymond Chen 所说的全局解决方案一个局部问题,结果打破了系统其他部分的预期。
如果您想明确控制正在使用的线程,那么您应该创建自己的实现,但是除非您真的知道自己在做什么,否则最好让 .Net 框架处理线程管理。
关于c# - .NET CLR 线程池耗尽 - 实现错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23189090/
我们认为 Cloud Foundry 中的一组虚拟机存在 Azure SNAT 耗尽问题。这些机器不经过负载平衡器。 我已经浏览过这份文件: https://learn.microsoft.com/e
我正在使用 onSceneTouchEvent 在 TMX map 上移动玩家: @Override public Scene onCreateScene() { ...
关于这篇文章:Python del Statement , 我最近遇到了以下片段: # custom_process.py import threading import subprocess myL
我有一个具有多个线程的 python 应用程序,其中线程 2 到 n 可能会打开任意数量的文件。我想确保当线程 1 尝试打开文件时,它绝对不会因为文件描述符耗尽而失败。简而言之,我想保留文件描述符而不
我开发了一个 c# .net 4 应用程序,它每天对组织中的每台计算机(超过 70,000 台)执行 WMI 查询。由于与此线程无关的原因,我无法从服务器运行该应用程序,而是从我的 Windows X
我正在尝试在 pytorch 中实现 Yolo-v2。但是,我似乎只是通过网络传递数据而耗尽了内存。该模型很大,如下所示。但是,我觉得我在用我的网络做一些愚蠢的事情(比如不在某处释放内存)。网络在 c
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 9 年前。 Improve this qu
我在这里查看了几个与“太多客户”相关的主题,但仍然无法解决我的问题,所以我必须针对我的具体情况再次询问。 基本上,我设置了本地 Postgres 服务器并需要进行数万次查询,所以我使用了 Python
我正在使用 std::random_device 并想检查它的剩余熵。根据 cppreference.com: std::random_device::entropy double entropy()
我有以下 docker-compos.yml 文件: web: build: . ports: - "4200:4200" - "35729:35729" vo
如果 Linux 操作系统用完进程 ID 会怎样?是否会删除较旧的进程以释放空间以适应 future 的请求? 最佳答案 我假设您问的是达到进程限制时会发生什么。在这种情况下,系统不允许创建新进程,直
我们将 Azure SQL 用作单个数据库并在 DTU 定价模型下使用。我们有一个包含约 50M 条记录的表,我们想在单个字符串属性上添加一个新的非聚集索引。 问题是这是一个生产数据库。如果我使用简单
我们有多个服务总线监听器在应用服务内作为连续的 Azure Webjobs 运行。总共有 12 个监听器 Web 作业在同一个 S1 应用服务计划上运行。环境很小,每天总共大约有~1000-10000
Der Azure 网络专家, 我们的 Web 应用程序经常耗尽出站 TCP 连接。大多数出站连接实际上是 Azure 内部连接(SQL、BlobStore、后端服务)。但我们还没有虚拟网络和专用端点
我下载了一个简单的静态网络服务器的源代码 http://www.ibm.com/developerworks/systems/library/es-nweb/sidefile1.html 但是,我对第
我已经查看了有关 SO 的其他类似问题,但无法很好地将所有内容拼凑在一起。我有一个 Rails 应用程序(在 Heroku 上),它使用具有多进程和多线程的 Puma。我的应用程序还使用 Redis
在此代码中,如果我对 ParseForm() 调用进行注释,请求将按预期工作 package main import ( "fmt" "net/http" "net/url"
我不明白。 XSLX 表大约有 3MB 大,但即使是 1024MB 的 RAM 也不足以让 PHPExcel 将其加载到内存中吗? 我这里可能做错了什么: function ReadXlsxTable
我已配置 CachingConnectionFactory包装了一个 MQTopicConnectionFactory和 MQQueueConnectionFactory每个缓存大小设置为 10。 这
我正在检查 CodeEval 中的一些问题并在 PHP 中遇到这个奇怪的错误。我没有用其他语言遇到过这样的事情,所以我不知道为什么会发生这种情况。不包括整个答案(请不要帮我找到解决方案,除了 PHP
我是一名优秀的程序员,十分优秀!