用于预先分配数据并在Julia中传递数据的设计模式

时间:2019-01-30 23:47:51

标签: julia

我正在寻求改进如何为在大型数组和矩阵上运行的计算繁重程序编写Julia代码的某些方面。

有许多私有函数可以进行中间处理,并且该系统以前是用C ++设计的,其方式是由自定义对象显式处理内存,以避免不断地重新初始化和重新分配内存。这与Julia's tips on performance内联。

我发现这转化为朱莉娅的方式是:

mutable struct Bar
   # A data structure holding data for a domain object
end

mutable struct FooData
    # A data structure holding intermediate computation variables
    data::Array{Float32, 1}

    function FooData()
       new(Array{Float32, 1}(undef, 10000)
    end
end


function foo!(data::FooData, b::Bar, param1, param2)
    # modify data and return something
end

data = FooData()
for i=1:100
    foo!(data, ...)
end

通常是foo!做不止一件事。出于性能原因,这主要是为了合并操作。这使得命名foo和FooData特别困难。

我的问题是:

  1. 是否有更好的方式处理预分配数据?例如,C ++中的代码有一个单独的Singleton对象,该对象管理预分配的数据并传递指针。内存是使用malloc创建的,并且指针为void *,然后将其类型强制转换为所需的内容。它们不再需要时由manager对象释放。

  2. 您如何处理中间功能? Julia中没有封装来隐藏它们。你给他们起个不同的名字吗?

1 个答案:

答案 0 :(得分:3)

很难用一种更好的方式知道你的意思-怎么不好?在您的MWE中,根本不需要FooData类型,因为您可以传递一个Vector,但是实际用例可能更复杂。您不需要像在C ++中那样在对象中定义那么多的对象。

要回答第二个问题,局部函数通常被命名为_foobar。但是封装是由模块来处理的-您根本不会从模块中导出这些功能。它们不是private,您仍然可以根据需要使用它们(使用MyModule._foobar()),但这是您自己的责任。这种过分执行惯例在Julia中很常见。