为什么控制台应用程序和 WinForms 之间的性能差异如此之大?

Why do I have such a large performance difference between a Console app and WinForms?

我写了一些简单的 C# 代码来测试一个数是否是素数。当我 运行 WinForms 应用程序中的代码与控制台应用程序中的代码时,我很惊讶地发现性能存在巨大差异。

代码非常简单:

ulong num = 18446744073709551557;
Stopwatch stopwatch = Stopwatch.StartNew();
if (num % 2 == 0)
{
    stopwatch.Stop();
    MessageBox.Show("Composite " + stopwatch.ElapsedMilliseconds.ToString());
    return;
}
for (ulong i = 3; i <= Math.Sqrt(num); i += 2)
{
    if (num % i == 0)
    {
        stopwatch.Stop();
        MessageBox.Show("Composite " + stopwatch.ElapsedMilliseconds.ToString());
        return;
    }
}
stopwatch.Stop();
MessageBox.Show("Prime " + stopwatch.ElapsedMilliseconds.ToString());

对于控制台应用程序,我使用 Console.WriteLine() 而不是 MessageBox.Show()。现在我原以为性能差异可以忽略不计。但是,控制台应用程序的性能似乎始终不如 windows 表单应用程序。

由 Visual Studio 2022 编译,对于调试版本(运行 无调试),winforms 应用程序需要约 36000 毫秒,但控制台应用程序需要约 156000 毫秒。对于发布版本(运行 无调试),Winforms 约 35500 毫秒,控制台约 137000 毫秒。 (有趣的是,如果 运行 使用 调试,两者似乎 运行 稍微快一点。)这种差异的原因是什么?

我无法重现问题

这里是我在发布时的发现 运行 的总结,没有调试器(VS 中的 Ctrl-F5)。 Console 和 WinForms 的 32 位和 64 位进程之间存在显着差异。

IDE Platform Console WinForms
VS2017/NET 4.8 x32 43.94 sec 43.21 sec
VS2017/NET 4.8 x64 4.43 sec 4.38 sec
VS2022/NET 4.8 x32 43.62 sec 43.33 sec
VS2022/NET 4.8 x64 4.56 sec 4.45 sec
VS2022/NET 6.0 x64 4.46 sec 4.45 sec

注意:console 和 winforms 之间的差异在噪声范围内。

代码

两个项目的测试代码相同

internal static bool IsPrimeTest(ulong num)
{
    if (num == 2)
    {
        return true;
    }
    if (num % 2 == 0)
    {
        return false;
    }
    for (ulong i = 3; i <= Math.Sqrt(num); i += 2)
    {
        if (num % i == 0)
        {
            return false;
        }
    }
    return true;
}

和亚军

private void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    ulong x = 18446744073709551557ul;
    textBox1.Text = "Burn-in";
    Program.IsPrimeTest(x / 16);
    textBox1.Text = "Start timming";
    var sw = Stopwatch.StartNew();
    bool ok = Program.IsPrimeTest(x);
    sw.Stop();
    string bits = Environment.Is64BitProcess ? "x64" : "x32";
    textBox1.Text = $"Bits={bits}, Prime={ok}, Time={sw.Elapsed.TotalSeconds:f2} sec";
    button1.Enabled = true;
}

有趣 side-note,使用 Intel Fortran 进行的类似测试产生了 Time = 3.80 sec,它仅比 C# 快一点。诚然,Fortran 不支持无符号整数,因此必须使用全精度浮点数进行检查。每个 mod(x,p)==0 调用都被翻译成 x/p == int(x/p).