6

是的,一个微不足道的问题,但我找不到专家意见。

我正在使用计算表达式对服务器端进程进行排序。当我的函数具有相同的签名时,它对我有很大帮助,因此我有一个区分联合,其中定义了不同的组合。我有几个快速的初学者问题。

  1. DU 可以拥有的选项数量是否有推荐的上限?目前我的 DU 有九个选项,但这个数字会随着项目的进展而增加。如果我在项目结束时达到 30 或 40 怎么办?

  2. 如果某些选项变得“长”,可能会有问题吗?目前,平均期权有大约四五种基本类型——类似——bool * string * XElement * int * string但最长的一种具有以下定义:

    bool * int * int * int * string * XElement * XElement * DateTime 选项 * DateTime 选项 * string * Dictionary * Dictionary

我不希望有很多选择会在这么长的时间内出现。但是,我是否正在为性能方面的痛苦世界做好准备?

提前致谢。

4

2 回答 2

9

我认为您可以放心地假设,如果您的数据类型的大小与 F# 编译器使用的数据类型的大小相似,那么一切都会运行良好 - F# 编译器的性能是 F# 团队肯定关注的东西,所以我认为他们还进行了一些实验,以确保他们使用的受歧视工会有效地工作。

  • 至于案例数量,SynExpr歧视联合(见源码)有50多个案例,所以我认为应该没问题。

    可区分联合上的模式匹配是通过使用switch整数上的 IL 操作码来编译的,所以如果你想确定的话,你可以尝试对它的效率进行一些研究。此外,如果您只是match用来查找一个特定案例,那么这应该只是一个整数比较,而不管其他案例的数量。

  • 至于字段数,最长的情况SynExpr有7个字段,但我想你可以找到长度更长的其他DU。(我认为这个数量的属性的一个更大的问题是可读性 - 因为这些属性是未命名的。所以我认为对逻辑上属于一起的大量属性使用记录可能会更好。)

我认为你描述的 DU 的大小应该没问题,但我自己没有做过任何性能测试——所以如果你真的想确定,你需要测量它。(但正如我所说,我很确定这是作为 F# 编译器开发的一部分进行测试的东西)

于 2013-05-14T10:44:45.313 回答
6

如果记忆对我有用,我相信在 DU 上深度嵌套的模式匹配存在一些性能问题,每个案例有很多案例/字段,但那是 2.0 之前的版本,我相信他们修复了实现,因此目前这样的场景是优化良好,没有明显的性能问题。(对不起,没有引用)。

但即使经过优化,DU 也会将大量代码转化为大量代码。因此,即使它们的性能可能与任何等效的手动编码控制流一样好(并且可能更好),但可能会在为函数/方法体发出的大量指令上堆栈溢出(但这将是相当极端的情况,因为 .NET 默认堆栈大小约为 1MB,但是,它肯定会导致在涉及大 DU 匹配的非尾递归方法/函数中比通常更早的堆栈溢出,但也不太可能达到你应该真的害怕这种情况)。

我不相信它会改变性能特征(因为我们在任何一种情况下都在谈论堆分配的对象),但为了可维护性/可读性,它有时有助于将您的 DU 案例数据包装在记录类型中,以便命名数据字段和数据字段子集上的模式匹配更容易(例如{Name="Stephen"},而不是(_,_,_,_,_,_,_,"Stephen",_,_,_,_,_))。(@TomasPetricek 击败了我这个建议,在我第一次阅读他的回答时没有看到)

于 2013-05-14T13:06:47.083 回答