尝试解决核心亲和性问题会导致 UI 在重 CPU 负载下停滞
Trying to solve a core affinity problem results in UI stalling under heavy CPU load
我几乎没有线程方面的经验,所以请多多包涵。
我正在制作一个 monitoring/testing 工具,它监视硬件传感器并使用亲和掩码和 for 循环来一个接一个地循环遍历内核 运行 进行全负载单核压力测试。
问题是,当用户开始测试并设置亲和力时,它不是仅将测试方法分配给该核心,而是分配整个程序,这意味着 UI 只能 运行当前经过测试且处于满载状态的核心。
我想很明显 UI 只是在测试过程中停顿,输出监控数据的标签被冻结,而在测试过程中有相关读数是至关重要的,因为这是这个程序的主要目的。
经过一些研究,我认为我需要使用线程,但我以前从未使用过它。
这是我的缩短代码。问题是,当我在任何包含标签的方法上使用线程时,它会抛出错误“跨线程操作无效:控制 'CPUTempTDie' 从创建它的线程以外的线程访问”。我试图在新线程中启动 Report sensors,但没有帮助。我真的试图在一个新线程中启动涉及的每个方法和标签,但它要么没有帮助,要么控制分数(分数 - 是 TestMethod 返回的结果,用于将其与正确的数字进行比较以确认稳定性)或程序只是跳过部分代码,只说“完成”。
问题是:是否可以只设置一个TestingMethod
到一个特定的核心,允许程序的其余部分(包括UI)使用任何其他空闲核心,如果没有,我究竟应该在新线程中启动什么才能让 UI 在负载下更新?
//the method below updates labels and calls ReportSensors method that reads
//sensors on a timer tick
private void Monitoring()
{
sensor.ReportSensors(); //calls Method that reads sensors
//Two labels below are stalling when TestingMethod runs
CPUTempTDie.Value = (int)sensor.CpuTemp;
FrequencyLabel.Text = sensor.CoreFrequency.ToString("0") + "MHz";
}
private int TestingMethod()
{
while (true)
{
//Performs calculations to generate load, returns the "score"
}
if (timer.Elapsed.TotalSeconds > 60)
{
break;
}
return score;
}
private async void PerCoreTest()
{
try
{
await Task.Delay(3000);
for (int i = 0; i < (numberOfCores); i++)
{
coreCounter++;
Thread.BeginThreadAffinity();
SetThreadAffinityMask(GetCurrentThread(), new IntPtr(intptrVal));
//TestingMethod below being called twice, and results from both runs
//are later compared for consistency.
TestingMethod();
iter1 = score / 10000;
TestingMethod();
iter2 = score / 10000;
maxScore = Math.Max(iter1, iter2);
await Task.Delay(1000);
TestLabel.Text = score.ToString();
//Switches to the next thread mask
}
}
finally
{
Thread.EndThreadAffinity();
}
}
private void TestButton_Click(object sender, EventArgs e)
{
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.High;
PerCoreTest();
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.Normal;
}
澄清:尽管 linked thread 没有回答我的问题,但我的问题已作为重复问题关闭。我要求重新打开它,因为:
虽然链接线程中提到的“大量远程调用大约 2000 - 3000 次调用”在某些硬件上可能很重,但这与计算 CPU 不同在 while(true) 循环中,如果 UI 位于同一个核心上,它会从任何类型的硬件中榨取所有性能,因为 UI 什么都没有。
据称我重复的线程中的建议解决方案无法解决问题,我原来的问题完全不同:我无法弄清楚必须在任务中放置什么才能使 UI 运行 负载平稳
我帖子下评论的建议也没有回答这个问题。我尝试了解决方案
Panagiotis Kanavos(见下文)但问题仍然存在:
while (true)
{
await Task.Delay(500);
await Task.Run(() => sesnor.ReportSensors());
}
研究类似主题后,似乎 none 解决了我的特定问题。
您正在为 UI 线程设置 CPU 亲和力,然后 运行 在同一线程上设置测试例程,因此您的 UI 是有意义的考试的时候挂了。在您开始实际执行测试例程之前,简化事情并确保您的 UI/threading 正常工作。
private int TestingMethod()
{
// set affinity for current thread here when ready
// mock a busy thread by sleeping
System.Threading.Thread.Sleep( 15 * 1000 );
return 42;
}
// don't use `async void`
private async Task PerCoreTest()
{
TestLabel.Text = "Running...";
// we're in the UI thread, so we want to run
// the test in another thread. run a new
// task to do so, await result so the continuation
// will execute back in the UI thread
var score = await Task.Run(() => TestingMethod());
TestLabel.Text = score.ToString();
}
private async Task TestButton_Click(object sender, EventArgs e)
{
await PerCoreTest();
}
漂亮又简单。在表格中添加其他东西,每秒钟左右更新一次,或者添加一个按钮,您可以单击以验证 UI 是否正确更新,因为测试例程是 运行ning.
一旦您确认 UI 没有锁定,您就可以开始向您的测试例程添加内容。我建议首先获得一个没有处理器亲和力的工作测试例程。
private int TestingMethod()
{
var score = 0;
// set affinity for current thread here when ready
do
{
// your cpu-frying logic
}
while( /* sentinel condition */ )
return score;
}
再次验证 UI 在测试期间是否有响应,您还可以验证您的一个核心是否被滥用。一旦验证了所有这些,您就可以设置线程亲和性 INSIDE TestingMethod()
方法的实现(将其抽象为另一个方法调用很好,只要它是从内部调用的TestingMethod
的主体,而不是 运行 在 Task
或其他线程中。您可以将掩码作为参数从 PerCoreTest
传递到 TestingMethod
方法。
这应该会让您走上正确的轨道,去做您想做的事。我建议您花一些时间阅读有关多线程的一般知识和 .NET 的 threading/asynchronous 编程模型,如果您打算在未来继续使用它的话。
我几乎没有线程方面的经验,所以请多多包涵。 我正在制作一个 monitoring/testing 工具,它监视硬件传感器并使用亲和掩码和 for 循环来一个接一个地循环遍历内核 运行 进行全负载单核压力测试。 问题是,当用户开始测试并设置亲和力时,它不是仅将测试方法分配给该核心,而是分配整个程序,这意味着 UI 只能 运行当前经过测试且处于满载状态的核心。 我想很明显 UI 只是在测试过程中停顿,输出监控数据的标签被冻结,而在测试过程中有相关读数是至关重要的,因为这是这个程序的主要目的。
经过一些研究,我认为我需要使用线程,但我以前从未使用过它。 这是我的缩短代码。问题是,当我在任何包含标签的方法上使用线程时,它会抛出错误“跨线程操作无效:控制 'CPUTempTDie' 从创建它的线程以外的线程访问”。我试图在新线程中启动 Report sensors,但没有帮助。我真的试图在一个新线程中启动涉及的每个方法和标签,但它要么没有帮助,要么控制分数(分数 - 是 TestMethod 返回的结果,用于将其与正确的数字进行比较以确认稳定性)或程序只是跳过部分代码,只说“完成”。
问题是:是否可以只设置一个TestingMethod
到一个特定的核心,允许程序的其余部分(包括UI)使用任何其他空闲核心,如果没有,我究竟应该在新线程中启动什么才能让 UI 在负载下更新?
//the method below updates labels and calls ReportSensors method that reads
//sensors on a timer tick
private void Monitoring()
{
sensor.ReportSensors(); //calls Method that reads sensors
//Two labels below are stalling when TestingMethod runs
CPUTempTDie.Value = (int)sensor.CpuTemp;
FrequencyLabel.Text = sensor.CoreFrequency.ToString("0") + "MHz";
}
private int TestingMethod()
{
while (true)
{
//Performs calculations to generate load, returns the "score"
}
if (timer.Elapsed.TotalSeconds > 60)
{
break;
}
return score;
}
private async void PerCoreTest()
{
try
{
await Task.Delay(3000);
for (int i = 0; i < (numberOfCores); i++)
{
coreCounter++;
Thread.BeginThreadAffinity();
SetThreadAffinityMask(GetCurrentThread(), new IntPtr(intptrVal));
//TestingMethod below being called twice, and results from both runs
//are later compared for consistency.
TestingMethod();
iter1 = score / 10000;
TestingMethod();
iter2 = score / 10000;
maxScore = Math.Max(iter1, iter2);
await Task.Delay(1000);
TestLabel.Text = score.ToString();
//Switches to the next thread mask
}
}
finally
{
Thread.EndThreadAffinity();
}
}
private void TestButton_Click(object sender, EventArgs e)
{
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.High;
PerCoreTest();
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.Normal;
}
澄清:尽管 linked thread 没有回答我的问题,但我的问题已作为重复问题关闭。我要求重新打开它,因为:
虽然链接线程中提到的“大量远程调用大约 2000 - 3000 次调用”在某些硬件上可能很重,但这与计算 CPU 不同在 while(true) 循环中,如果 UI 位于同一个核心上,它会从任何类型的硬件中榨取所有性能,因为 UI 什么都没有。
据称我重复的线程中的建议解决方案无法解决问题,我原来的问题完全不同:我无法弄清楚必须在任务中放置什么才能使 UI 运行 负载平稳
我帖子下评论的建议也没有回答这个问题。我尝试了解决方案 Panagiotis Kanavos(见下文)但问题仍然存在:
while (true)
{
await Task.Delay(500);
await Task.Run(() => sesnor.ReportSensors());
}
研究类似主题后,似乎 none 解决了我的特定问题。
您正在为 UI 线程设置 CPU 亲和力,然后 运行 在同一线程上设置测试例程,因此您的 UI 是有意义的考试的时候挂了。在您开始实际执行测试例程之前,简化事情并确保您的 UI/threading 正常工作。
private int TestingMethod()
{
// set affinity for current thread here when ready
// mock a busy thread by sleeping
System.Threading.Thread.Sleep( 15 * 1000 );
return 42;
}
// don't use `async void`
private async Task PerCoreTest()
{
TestLabel.Text = "Running...";
// we're in the UI thread, so we want to run
// the test in another thread. run a new
// task to do so, await result so the continuation
// will execute back in the UI thread
var score = await Task.Run(() => TestingMethod());
TestLabel.Text = score.ToString();
}
private async Task TestButton_Click(object sender, EventArgs e)
{
await PerCoreTest();
}
漂亮又简单。在表格中添加其他东西,每秒钟左右更新一次,或者添加一个按钮,您可以单击以验证 UI 是否正确更新,因为测试例程是 运行ning.
一旦您确认 UI 没有锁定,您就可以开始向您的测试例程添加内容。我建议首先获得一个没有处理器亲和力的工作测试例程。
private int TestingMethod()
{
var score = 0;
// set affinity for current thread here when ready
do
{
// your cpu-frying logic
}
while( /* sentinel condition */ )
return score;
}
再次验证 UI 在测试期间是否有响应,您还可以验证您的一个核心是否被滥用。一旦验证了所有这些,您就可以设置线程亲和性 INSIDE TestingMethod()
方法的实现(将其抽象为另一个方法调用很好,只要它是从内部调用的TestingMethod
的主体,而不是 运行 在 Task
或其他线程中。您可以将掩码作为参数从 PerCoreTest
传递到 TestingMethod
方法。
这应该会让您走上正确的轨道,去做您想做的事。我建议您花一些时间阅读有关多线程的一般知识和 .NET 的 threading/asynchronous 编程模型,如果您打算在未来继续使用它的话。