65.9K
CodeProject 正在变化。 阅读更多。
Home

如何确定 Silverlight 网页的处理器数量

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (11投票s)

2009 年 2 月 8 日

CPOL

4分钟阅读

viewsIcon

39771

downloadIcon

96

如何在不使用任何特殊权限的情况下,判断一台计算机是否有多个CPU。

并行编程需要一种简单的方法来判断用户是否有多核CPU。

现在大多数新计算机都拥有多个处理器,我们看到并行编程的使用正在迅速增长。许多库已经提供了针对多核处理器计算机的高效代码,但是你如何知道你正在运行的计算机是否真的拥有不止一个CPU呢?

为什么识别多核CPU的需求现在变得如此紧迫?

当今大多数程序都是多线程的。越来越多的库被编写用于有效的多线程代码,并假设这些代码将在多核计算机上运行。了解计算机是否是多核的这一需求是必须的,但在某些情况下,例如Web应用程序,你无法直接“询问”操作系统它正在使用多少个核心。

这“通常”是如何解决的?

在.NET环境中运行时,你可以通过以下方式轻松获得精确的处理器数量:

System.Environment.ProcessorCount;

坏消息是,在没有权限询问操作系统关于系统运行的处理器数量的情况下,这个属性是不可用的。当你开发基于MS Silverlight或Adobe Flash的网页和RIA时,正是这种情况。

在Silverlight应用程序或类似的RIA情况下,如何识别多个CPU?

我编写了以下代码,仅使用任何语言和任何平台上都可用的基本操作来确定机器是否是多核的。该代码并行运行两个线程,并检查它们是否真的可以同时运行。

SpinWait - 神奇的钥匙

大致来说,线程的“时间片”(Quanta)是操作系统在不进行上下文切换的情况下分配给该线程的最短时间。它通常在10到15毫秒之间。我编写的代码让处理器在给定的指令数量内保持忙碌,例如创建一个带有递增索引的空循环;然而,与`Sleep`不同的是,此代码会阻止线程进行上下文切换,除非它旋转的时间超过了线程的时间片。

这是我使用的代码

// will indicate that the computer has more than one processor
bool moreThanOne = false;
// will close the other thread eventually
bool toContinue = true;
ManualResetEvent m = new ManualResetEvent(false);
// open the secondary thread
Thread t = new Thread(new ThreadStart(delegate
{
    // make sure it has time to start
    m.Set();
    // set the flag while not signaled to stop
    while (toContinue)
        moreThanOne = true;
}));
t.IsBackground = false;
t.Start();
// waiting for the thread to start
m.WaitOne();
// forcing context switch
Thread.Sleep(0);
// begining of the threads quanta
moreThanOne = false;
// spin for a short time. Enough for the other thread to set the flag
// but still shorter than the quanta
Thread.SpinWait(100000);
// stop the secondary thread
toContinue = false;
// return the result
return moreThanOne;

注意:此方法描述的方法并非确定性的,因为操作系统可能由于系统中断或其他原因要求上下文切换,在这种情况下,代码可能会报告计算机拥有多个核心,尽管实际上只有一个核心。

该代码打开一个线程,专门用于反复设置一个布尔标志,目的是让该线程在存在辅助核心的情况下运行在辅助核心上。为了确保线程已启动并准备好循环,使用了“等待”句柄。主线程等待辅助线程启动,然后调用`Thread.Sleep(0)`强制进行上下文切换。这确保了下一条指令将在线程时间片的开始处执行。为了在我们仍在旋转的同时允许另一个线程在另一个核心上设置标志,我们“SpinWait”100000条指令。由于“SpinWait”比线程的时间片短,它不会强制上下文切换。现在,我们可以检查我们的结果:如果在经过的时间内设置了该标志,我们就知道它一定是另一个处理器在该进程忙于旋转时处理了该线程。

实现和使用

我在研究我们的http://www.headup.com应用程序的性能时,开发了上述代码。我发现我们浪费了大量时间在强制性锁上,这些锁虽然是必需的,但并没有证明所产生的开销是合理的。

自旋锁 - 物有所值,成本低廉

经过一些研究,我决定使用“SpinLock”实现,它利用计算机的两个核心来创建一个高效的锁,从而以非常低的成本提升我们应用程序的性能。`SpinLock`的秘密在于,它不使用像`lock`那样的系统调用,而是使用`SpinWait()`来让另一个核心释放锁。当然,如果计算机没有另一个核心,这样做是徒劳的。因此,为了知道我是否能够有效地使用`SpinLock`,我首先需要验证我运行的机器是否拥有一个以上的处理器。因此有了上面的代码……

示例和注意事项

  1. 有几种“SpinLock”实现,我发现这个特别好:http://www.bluebytesoftware.com/blog/PermaLink,guid,fd6ed0d7-2849-4ca1-9619-74cd5713c3c0.aspx
  2. 您可以亲自测试我的处理器检测器:http://yogil.com/yogi/processors.html。您可以通过在“我的电脑”(Windows机器)上单击“属性”来手动查看您的计算机正在运行多少个处理器。

未来的想法

  • 由于存在误报的风险,最好多次运行该方法并使用最常见的结果。这肯定会提高结果的准确性。
  • 通过使用多线程,应该可以发现处理器的确切数量,而不仅仅是机器是否有一个或多个。
© . All rights reserved.