首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >F# - fsc.exe挂起大文件

F# - fsc.exe挂起大文件
EN

Stack Overflow用户
提问于 2019-02-03 19:01:14
回答 1查看 119关注 0票数 1

我做了一些有机化学模型。模型由生成的ModelData.fs文件描述,例如:https://github.com/kkkmail/ClmFSharp/blob/master/Clm/Model/ModelData.fs。该文件的结构非常简单,使用生成的模型文件是它可能工作的唯一方法。

所引用的文件仅用于测试,但真正的模型是巨大的,可能接近60-70MB/150万LOC。当我试图编译这样的文件时,F#编译器fsc.exe就会挂断,再也不会回来了。它“吃掉”大约1.5GB的内存,然后在几乎100%的处理能力下永远做一些事情。它可以很清楚地处理较小的型号,大约需要10 MB在一分钟之内。因此,在fsc中,在10 MB到70 MB之间的某个地方会出现严重故障。

我想知道是否可以对fsc编译项目的方式进行一些参数调整,以使其能够处理如此庞大的模型。

我所指的大型模型有一个参数集如下:let numberOfSubstances = 65643。这将产生大小相同的各种数组。我想知道这是否是问题的根源。

非常感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-04 14:50:03

我不认为你需要自动生成所有这些。

从您的评论中,我了解到函数d0d1,.是从一个大的稀疏矩阵中生成的,它可以将所有的输入数组x (用系数)加起来,但关键是跳过零系数的求和,这给了你很大的性能增益,因为这个矩阵是巨大的。这是正确的评估吗?

如果是这样的话,我仍然不认为您需要生成代码来做到这一点。

让我们来看看。我将假设您的巨型稀疏矩阵有一个获取单元值的接口,它看起来如下所示:

代码语言:javascript
复制
let getMatrixCell (i: int) (j: int) : double
let maxI: int
let maxJ: int

那么您的自动生成代码可能如下所示:

代码语言:javascript
复制
let generateDFunction (i: int) =
    printfn "let d%d (x: double[]) =" i
    printfn "    [|"
    for j in 0..maxJ do
        let cell = getMatrixCell i j
        if cell <> 0 then
            printfn "        %f * x.[%d]" cell j
    printfn "    |]"
    printfn "    |> Array.sum"

这会导致这样的结果:

代码语言:javascript
复制
let d25 (x : array<double>) = 
    [|
        -1.0 * x.[25]
        1.0 * x.[3]
    |]
    |> Array.sum

注意,我在这里简化了:在您的示例文件中,函数看起来也是由x.[i]乘以负系数。但也许我也太复杂了,因为看起来所有的系数都是1-1。但这对我来说并不重要。

现在,在注释中,有人建议您不要生成函数d0d1,.而是直接与矩阵一起工作。例如,这将是对这种建议的天真实施:

代码语言:javascript
复制
let calculateDFunction (i: int) (x: double[]) =
    [| for j in 0..maxJ -> (getMatrixCell i j) * x.[j] |] |> Array.sum

然后,您认为这个解决方案会慢得令人望而却步,因为它总是迭代整个数组的x,这是很大的,但是大部分系数都是零,所以它不必这样做。

然后,解决这个问题的方法是使用生成代码的中间步骤:生成只涉及非零指标的函数,然后编译和使用这些函数。

但是重点是:是的,你确实需要一个中间的步骤来消除非零指标,但是它不需要生成和编译代码!

相反,您可以提前准备非零指标的列表/数组:

代码语言:javascript
复制
let indicies = 
    [| for i in 0..maxI ->
        [ for j in 0..maxJ do
            let cell = getMatrixCell i j
            if cell <> 0 then yield (j, cell)
        ]
    |]

这将产生一个数组indicies : Array<int list>,其中每个索引k对应于您的自生成函数dk,它包含一个非零矩阵的列表以及它们在矩阵中的值。例如,上面给出的函数d22将由indicies的第22元素表示。

代码语言:javascript
复制
indicies.[22] = [ (25, -1.0), (3, 1.0) ]

根据这个中间结构,您可以计算任意函数dk

代码语言:javascript
复制
let calculateDFunction (k: int) (x: double[]) =
    [| for (j, coeff) in indicies.[k] -> coeff * x.[j] |] |> Array.sum

事实上,如果性能对您至关重要(从注释中可以看出),那么您可能应该取消所有这些中间数组:在每次迭代中分配数百或数千个堆绝对没有帮助。您可以用可变变量和:

代码语言:javascript
复制
let calculateDFunction (k: int) (x: double[]) =
    let sum = 0.0
    for (j, coeff) in indicies.[k] do
        sum <- sum + coeff * x.[j]
    sum
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54506429

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档