【问题标题】:F# execution speed difference between visual studio and the command line generationF# Visual Studio 和命令行生成的执行速度差异
【发布时间】:2019-11-02 22:32:34
【问题描述】:

使用 F# Visual Studio(社区 2019)和 F# 命令行(均使用 F# 4.7)构建的程序在执行时间上存在显着差异。我的问题:为什么会有这种差异?

我使用的是 Windows 10 家庭版 1809(最新)。该程序主要在 Pollard rho 因式分解算法中使用大整数(下面的程序)。对于 Visual Studio,我使用了一个控制台项目。

Visual Studio 的运行时间为 28 秒,命令行运行时间为 39 秒。

我在两者上都使用了 x64 目标的发布二进制文件。我尝试了许多 fsc 编译命令行选项(--debug- --optimize+ --standalone),没有任何明显的区别。

命令行编译输出为

 7168 Nov  2 16:14 rho.exe

命令行

fsc rho.fs

如上所述,添加命令行选项并没有太大区别。

Visual Studio 的输出是

 10752 Nov  2 09:12 rho0.dll*
159744 Nov  2 09:12 rho0.exe*

所以输出是非常不同的。 rho 和 rho0 是同一个源。

两个版本产生相同的答案,但经过的时间差异很大。为什么?

程序是:

open System
open System.Diagnostics
open System.Numerics

type Z = System.Numerics.BigInteger

let rho n maxIter c1 =
  let mutable iter = 1
  let mutable prod = 1I
  let mutable x    = 2I
  let mutable y    = 11I
  let mutable gcd  = 0I
  let mutable solution = false

  let stopWatch = Stopwatch();
  stopWatch.Start()

  while not solution do
    x <- (x * x + c1) % n;
    y <- (y * y + c1) % n;
    y <- (y * y + c1) % n;
    prod <- ((y - x) * prod) % n;
    if (iter % 150 = 0) 
    then
      gcd <- Z.GreatestCommonDivisor (n, prod)
      if (gcd <> 1I) then
        stopWatch.Stop()
        printfn "rho c1 = %A" c1
        printfn "factor, iterations = %A, %A" gcd iter
        printfn "elpased time = %A" stopWatch.ElapsedMilliseconds
        solution <- true
      else
        prod <- 1I
        iter <- iter+1
    else
      iter <- iter+1
  if (not solution) then
    printfn "no solution, iterations = %A" iter
  else printfn "solution"


let n = Z.Pow(2I,257) - 1I
let maxIter = 30000000
printfn "calling rho"
let result = rho n maxIter 7I

2019 年 11 月 4 日更新:

我在命令行中使用 .Net core 构建了一个项目(https://docs.microsoft.com/en-us/dotnet/fsharp/get-started/get-started-command-line 的说明)

应用程序在 28 秒内运行。所以看起来,当你在命令行上使用 fsc 时,它使用的是 .NET Framework,但如果你用 .NET Core 制作命令行项目,运行时间会显着减少。 Visual Studio 控制台应用程序的默认设置是使用 .Net Core。

在 VS 中,如果我将框架从 .NET Core 更改为 .NET Framework,运行时间会增加到 39 秒。

【问题讨论】:

  • 在 F# 中有很多值得喜欢的地方,但 bigintegers 很慢。 Windows 10 和 linux 上的 Ocaml 运行时间为 10 秒,而 F# 上的运行时间为 28 秒
  • 在我看来,VS 在这里使用 dotnet 核心是因为 dll。我会使用像 dnspy 这样的工具来检查生成的输出。例如,它使用的是同一个大整数吗?
  • 您实际上并没有提出问题。我的猜测是差异可能是目标框架。如果 VS 项目以 .NET Core 为目标,而 fsc 命令以 .NET Framework 为目标,那么这可能会导致差异。您是否尝试过 dotnet build 或 dotnet run?另外,请显示您运行的命令行。而且,您可以将 VS 和 fsc 设置为返回详细输出以获取更多详细信息。
  • 您能分享一个重现性能差异的独立示例吗?这样我就可以在本地构建它,看看会发生什么。
  • F# 控制台应用程序的默认框架是 .NET Core 3.0(运行时间 28 秒)。如果我将 VS 项目更改为 .NET Framewok 4.5.1,则运行时间为 39 秒。这是为什么呢??

标签: .net visual-studio .net-core f#


【解决方案1】:

我采用了您的示例代码并通过不同的配置运行它:

.NET Core from VS Release x64 - 37214 ms with (9171, 3, 0) CC
.NET Core from VS Release x86 - 69903 ms with (7673, 6, 0) CC
.NET Core from VS Release Any - 35694 ms with (9171, 3, 0) CC

.NET Core using EXE Release x64 - 37995 ms with (9171, 3, 0) CC
.NET Core using EXE Release x86 - 72489 ms with (7673, 7, 0) CC
.NET Core using EXE Release Any - 36106 ms with (9171, 3, 0) CC

.NET Framework 4.7.2 from VS Release x64 - 49697 ms with (5935, 4, 0) CC
.NET Framework 4.7.2 from VS Release x86 - 81324 ms with (4945, 8, 0) CC
.NET Framework 4.7.2 from VS Release Any - 80521 ms with (4945, 8, 0) CC

.NET Framework 4.7.2 using EXE Release x64 - 49450 ms with (5935, 4, 0) CC
.NET Framework 4.7.2 using EXE Release x86 - 80418 ms with (4945, 8, 0) CC
.NET Framework 4.7.2 using EXE Release Any - 80458 ms with (4945, 8, 0) CC

.NET Core using dotnet run x64 - 37614 ms with (9171, 3, 0) CC
.NET Core using dotnet run no tiered compilation x64 - 37186 ms with (9171, 3, 0) CC

由此看来,x86x64 之间似乎有很大的不同。您是否尝试过在 VS 和命令行中强制 x64 模式。 Dll 可以编译为 Any,但仍优先使用 x86。

另外;从我的测试来看,.NET Core 的性能似乎优于 .NET Framework 4.72。

我尝试在 .NET Core 中禁用分层编译,这有时会导致性能问题,但无法发现任何真正的区别。

我意识到这在 StackOverflow 中是不受欢迎的,但由于项目配置可能很难放入帖子中,因此我决定将我使用的示例代码放在这里:https://github.com/mrange/CodeStack/tree/master/q58675873/FsPerfSo

OP 可以查看是否可以在 OPs 机器上复制我的号码。

所以从我的角度来看,.NET Core 看起来比 .NET Framework 更好,但为什么呢?

通过dnSpy查看代码,我无法看出 .NET Core 或 .NET Framework 的 OP 代码之间存在显着差异。但是,通过查看 System.Numerics 依赖项,我可以发现 .NET Core 和 .NET Framework 版本的 System.Numerics 之间存在一些非常显着的差异。

System.Numerics 的版本在 .NET Core 中较新,但不确定它们是否遵循相同的版本控制(4.1.2.0 用于 .NET Core,4.0.0.0 用于 .NET Framework)。

因此,从我的角度来看,最重要的是,请确保使用 x64 和 .NET Core。

【讨论】:

    猜你喜欢
    • 2011-01-15
    • 2012-03-05
    • 2023-03-08
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多