Julia-具有属性的可变结构,该属性是一个函数和@code_warntype

时间:2018-10-25 14:58:13

标签: performance struct julia

在Julia中,我想使用一个可变的结构,该结构具有一个类型为Function的属性,该函数将带有参数:

mutable struct Class_example
    function_with_arguments::Function
    some_attribute::Int
    function Class_example() new() end
    function Class_example(function_wa::Function, some_a::Int)
        this = new()
        this.function_with_arguments = function_wa
        this.some_attribute = some_a
        this
    end
end

我也想对该可变结构执行操作:

function do_action_on_class(Class::Class_example)
    return Class.function_with_arguments(Class.some_attribute ,2.0, true)
end

然后我定义一个旨在成为我的类属性的函数:

function do_something_function(arg1::Int, arg2::Float64, arg3::Bool)
    if arg2 < 5.0
        for i in 1:arg1
            # Do Something Interesting
            @show arg3
        end
    end
    return 1
end

最后,function_whith_arguments将在我的整个项目中启动大量时间,这只是一个最小的示例,因此我希望所有这些代码都非常快速。这就是为什么我根据Julia的文档Performance Tips

使用@code_warntype的原因

但是,@code_warntype告诉了我

body::Any
15 1 ─ %1 = (Base.getfield)(Class, :function_with_arguments)::Function
getproperty
%2 = (Base.getfield)(Class, :some_attribute)::Int64
%3 = (%1)(%2, 2.0, true)::Any                                     │ 
return %3              

此处::Function和两个::Any为红色,表明Julia可以通过更好的实现来提高代码的性能。那么正确的实现是什么?我应该如何在可变结构中将属性function_whith_arguments声明为Function类型?

整个代码均可编译:

mutable struct Class_example
    function_with_arguments::Function
    some_attribute::Int
    function Class_example() new() end
    function Class_example(function_wa::Function, some_a::Int)
        this = new()
        this.function_with_arguments = function_wa
        this.some_attribute = some_a
        this
    end
end


function do_action_on_class(Class::Class_example)
    return Class.function_with_arguments(Class.some_attribute ,2.0, true)
end

function do_something_function(arg1::Int, arg2::Float64, arg3::Bool)
    if arg2 < 5.0
        for i in 1:arg1
            # Do Something Interesting
            @show arg3
        end
    end
    return 1
end

function main()
    class::Class_example = Class_example(do_something_function, 4)
    @code_warntype do_action_on_class(class)
end

main()

1 个答案:

答案 0 :(得分:5)

这将是有效的(可以推断)。请注意,我只修改(并重命名)了类型。

mutable struct MyClass{F<:Function}
    function_with_arguments::F
    some_attribute::Int
end


function do_action_on_class(Class::MyClass)
    return Class.function_with_arguments(Class.some_attribute ,2.0, true)
end

function do_something_function(arg1::Int, arg2::Float64, arg3::Bool)
    if arg2 < 5.0
        for i in 1:arg1
            # Do Something Interesting
            @show arg3
        end
    end
    return 1
end

function main()
    class::MyClass = MyClass(do_something_function, 4)
    @code_warntype do_action_on_class(class)
end

main()

我做了什么?

  • 如果您关心性能,则应该never have fields of an abstract typeisabstracttype(Function) == true。相反,您应该在该字段类型上进行参数化(上面的F,可以是任何函数。请注意,isconcretetype(typeof(sin)) == true)。这样,对于MyCall的任何特定实例,在编译时就可以知道每个字段的确切具体类型。

  • 性能的Irelevant,但:不需要将所有参数都分配给所有字段的构造函数。这样的constructor是默认隐式定义的。

您可以阅读有关参数类型here的更多信息。

顺便提一句,您所做的工作很像尝试用Julia编写OO风格。我建议不要这样做,而应使用Julia并使用多次调度的Julia方法。