如何避免Julia出现StackOverflow错误?

时间:2019-02-06 00:55:48

标签: out-of-memory julia stack-overflow

这是一个小乘积函数,它将一个常量列表,一个运算符列表和另一个常量列表转换为Julia Expr。 该函数适用于较小的常量集,但是对于包含100个常量和5个运算符的更多列表,该函数将引发StackOverflow。

function applyProduct(left, operators, right)
    prod = Iterators.product(left, operators, right)
    prod = Iterators.vcat(prod...)
    return Iterators.map(x -> Expr(:call, Symbol(x[2]), Symbol(x[1]), Symbol(x[3])), prod)
end

我的功能在vcat功能上爆炸了:

ERROR: LoadError: StackOverflowError:
Stacktrace:
[1] promote_eltypeof(::Tuple{String,typeof(+),Expr}, ::Tuple{String,typeof(+),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1211 (repeats 8406 times)
[2] _cat(::Val{1}, ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1382
[3] #cat#104(::Val{1}, ::Function, ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1511
[4] (::getfield(Base, Symbol("#kw##cat")))(::NamedTuple{(:dims,),Tuple{Val{1}}}, ::typeof(cat), ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\none:0
[5] vcat(::Tuple{String,typeof(*),Expr}, ::Tuple{String,typeof(*),Expr}, ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1449

这是一个堆栈溢出错误,因此数据以某种方式存储在堆栈中。我应该声明一些内容以保留在内存中吗?

我想将此操作应用于大量常量。也许我没有使用最有效的方法。

2 个答案:

答案 0 :(得分:3)

在需要列表元素之前,不要具体化列表:

using IterTools
function applyProduct2(left, operators, right)
    prod = Iterators.product(left, operators, right)
    return IterTools.imap(x -> Expr(:call, Symbol(x[2]), Symbol(x[1]), Symbol(x[3])), prod)
end

请注意,您可能需要安装IterTools.jl库。

这表示您的代码在vcat上崩溃,您尝试在其中使用大量参数对其进行调用。如果必须实现,请改用vec(collect(prod))

答案 1 :(得分:3)

您肯定要预先分配。并避免显式枚举product迭代器和使用映射

function applyproduct(left, op, right)
    itr = Iterators.product(op, left, right)
    thestack = Vector{Expr}(undef, length(itr))

    for (i, t) in enumerate(itr)
        thestack[i] = Expr(:call, Symbol.(t)...)
    end

    return thestack
end

N = 500
left = [String(rand('a':'z', rand(1:5))) for _ in 1:N]
right = [String(rand('a':'z', rand(1:5))) for _ in 1:N]
op = ["+", "-", "/", "^", "<", "≤"]

applyproduct(left, op, right)
# 1500000-element Array{Expr,1}:
#  :(wtolz + kzyxh)
#  :(wtolz - kzyxh)
#  ⋮             

此外,您可以通过以下方式避免进行Expr调用:

:($(Symbol(t[1]))($(Symbol(t[2])), $(Symbol(t[3]))))  
# :(adsf - sd)