【发布时间】:2020-07-04 16:45:45
【问题描述】:
我从一个基本的 Winforms 应用程序开始,每三秒获取一次当前 CPU 时钟速度,并用检索到的值刷新一个标签。
起初我使用线程定时器,但我认为这是“不好的做法”,因为它消耗线程。所以,我使用 BackgroundWorker 类来完成这项工作。不幸的是,该程序仍然每三秒冻结一次。
特此部分代码片段:
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 10; i++) {
GenerateDelay(3000);
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
GetCurrentCpuSpeed();
}
private void GetCurrentCpuSpeed()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
foreach (ManagementObject obj in searcher.Get()) {
var clockSpeed = obj["CurrentClockSpeed"].ToString();
lblCurrentClockSpeed.Text = clockSpeed;
}
}
private void GenerateDelay(int miliseconds)
{
Thread.Sleep(miliseconds);
}
我也尝试过这种方法作为一种变体:
private void GetCurrentCpuClockSpeed()
{
using (ManagementClass mc = new ManagementClass("win32_processor"))
{
var instances = mc.GetInstances();
foreach (var item in instances) {
try {
lblCurrentClockSpeed.Text = item.Properties["CurrentClockSpeed"].Value.ToString();
}
catch (Exception ex) {
throw;
}
}
}
}
编辑:根据 cmets 更改代码以使用 Timer。删除了我的“回复帖”。
以下是一些代码片段:
private void Form1_Load(object sender, EventArgs e)
{
CreateAndStartTimer();
}
private void CreateAndStartTimer()
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 3000;
t.Tick += new EventHandler(GetCurrentCpuSpeed2);
t.Start();
}
private void GetCurrentCpuSpeed2(object sender, EventArgs e)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
foreach (ManagementObject obj in searcher.Get()) {
var clockSpeed = obj["CurrentClockSpeed"].ToString();
lblCurrentClockSpeed.Text = "";
lblCurrentClockSpeed.Text = clockSpeed;
}
}
编辑 2:
我搞定了 :)
这是我的代码片段:
private void Form1_Load(object sender, EventArgs e)
{
CreateAndStartTimer();
}
private async void CreateAndStartTimer()
{
// Create an AutoResetEvent to signal the timeout threshold in the
// timer callback has been reached.
var autoEvent = new AutoResetEvent(false);
await Task.Run(() => new System.Threading.Timer(GetCurrentCpuClockSpeed, autoEvent, 1000, 1000));
}
private void GetCurrentCpuClockSpeed(object sender)
{
bool isCallerOnDifferentThread = lblCurrentClockSpeed.InvokeRequired;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
foreach (ManagementObject obj in searcher.Get()) {
var clockSpeed = obj["CurrentClockSpeed"].ToString();
if (isCallerOnDifferentThread) {
lblCurrentClockSpeed.Invoke(new Action(() => { lblCurrentClockSpeed.Text = clockSpeed; }));
}
}
}
【问题讨论】:
-
这是使用计时器的一个非常复杂的替代方案...您的方法消耗单个线程,计时器不消耗。
-
@canton7:感谢您的回复!我认为 Backgroundworker 在单独的线程上工作,所以我不会“伤害”用户界面。这就是我选择这种方法的原因。
-
backgroundWorker1_DoWork在单独的线程上调用,但它所做的只是让该线程休眠并每隔一段时间调用ReportProgress。GetCurrentCpuSpeed仍然在主线程上调用。调用GetCurrentCpuSpeed的 Timer 会做同样的事情,但不会抓住整个线程只是为了让它休眠 -
定时器不会损害或停止 UI 线程。
-
你可以edit你的问题包含更新的代码
标签: c# winforms wmi backgroundworker