You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中使用Timer统计质数计算的耗时?

问题分析与解决方案

你的问题出在UI线程被完全阻塞了。Windows Forms的Timer控件是依赖UI消息队列触发Tick事件的,当你在button1_Click里执行那个耗时的双重质数计算循环时,UI线程全程忙着做计算,根本没机会处理Timer的Tick消息——也就是说timer1_Tick方法从头到尾都没被调用过,time变量自然一直是0。

如果一定要用Timer来实现耗时统计,核心思路是不能让计算任务阻塞UI线程,得把计算放到后台线程执行,这样UI线程才能正常响应Timer的事件。下面给你两种可行的实现方案:

方案1:用BackgroundWorker后台执行计算(WinForms推荐)

BackgroundWorker是WinForms专门为后台任务设计的组件,自带线程安全的进度和完成通知,很适合这种场景:

  1. 给窗体添加一个BackgroundWorker控件(命名为backgroundWorker1),在属性面板开启WorkerReportsProgress和WorkerSupportsCancellation;
  2. 替换原按钮点击事件和新增后台任务逻辑:
private double time = 0;

private void button1_Click(object sender, EventArgs e)
{
    time = 0;
    timer1.Start();
    // 启动后台计算任务
    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    bool isPrime = true;
    // 这里优化了质数判断逻辑:内层循环只需要到sqrt(i),原代码效率极低
    for (int i = 2; i <= 200000; i++)
    {
        isPrime = true;
        for (int j = 2; j <= Math.Sqrt(i); j++)
        {
            if (i % j == 0)
            {
                isPrime = false;
                break;
            }
        }
        // 如果需要收集质数,可以存在List里,之后在完成事件更新UI
        // if (isPrime) ((List<int>)e.Result).Add(i);
    }
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    timer1.Stop();
    MessageBox.Show(time.ToString("F3") + "ms");
    // 若收集了质数,在这里安全更新ListBox
    // if (e.Result is List<int> primes)
    // {
    //     foreach (var prime in primes) listBox1.Items.Add(prime);
    // }
}

private void timer1_Tick(object sender, EventArgs e)
{
    time += 0.001;
}

方案2:用System.Timers.Timer(独立线程计时器)

这种Timer在独立线程触发事件,不受UI线程阻塞影响,但更新UI时需要手动Invoke到UI线程:

private double time = 0;
private System.Timers.Timer countTimer;
private bool isCalculating = false;

private void button1_Click(object sender, EventArgs e)
{
    time = 0;
    isCalculating = true;

    // 初始化1ms间隔的计时器
    countTimer = new System.Timers.Timer(1);
    countTimer.Elapsed += CountTimer_Elapsed;
    countTimer.Start();

    // 用Task启动后台计算
    Task.Run(() =>
    {
        bool isPrime = true;
        for (int i = 2; i <= 200000; i++)
        {
            isPrime = true;
            for (int j = 2; j <= Math.Sqrt(i); j++)
            {
                if (i % j == 0)
                {
                    isPrime = false;
                    break;
                }
            }
        }

        // 计算完成后停止计时器并更新UI
        isCalculating = false;
        countTimer.Stop();
        this.Invoke((Action)(() =>
        {
            MessageBox.Show(time.ToString("F3") + "ms");
        }));
    });
}

private void CountTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    if (isCalculating) time += 0.001;
}

额外优化提示

原代码的质数判断效率极低:内层循环不需要遍历到200000,只需要到Math.Sqrt(i)就足够了——如果i有大于平方根的因数,对应的另一个因数必然小于平方根,这样能把计算时间缩短几个数量级。

最后补充一句:虽然Timer可以实现耗时统计,但Stopwatch是更专业、精度更高的选择(基于系统高精度计时器),Timer的间隔受系统调度影响,精度会有误差。

内容的提问来源于stack exchange,提问作者camseats

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 17:57:59