(Julia 1.x)通过初始化变量增加分配?

(Julia 1.x)通过初始化变量增加分配?,julia,Julia,我正在编写的程序有一个用户编写的文件,其中包含要在代码中读取和实现的参数。用户应该能够通过使用注释字符(我使用了“#”,与Julia的约定)对输入文件进行分隔来对其进行注释-在解析输入文件时,代码将删除这些注释。在对这个解析器进行小优化的同时,我注意到在调用split()之前实例化第二个变量会对数字分配产生明显的影响: function removecomments1(line::String; dlm::String="#") str::String = "" try

我正在编写的程序有一个用户编写的文件,其中包含要在代码中读取和实现的参数。用户应该能够通过使用注释字符(我使用了“#”,与Julia的约定)对输入文件进行分隔来对其进行注释-在解析输入文件时,代码将删除这些注释。在对这个解析器进行小优化的同时,我注意到在调用
split()
之前实例化第二个变量会对数字分配产生明显的影响:

function removecomments1(line::String; dlm::String="#")
    str::String = ""

    try
        str, tmp = split(line, dlm)
    catch
        str = line
    finally
        return str
    end
end


function removecomments2(line::String; dlm::String="#")
    str::String = ""
    tmp::SubString{String} = ""

    try
        str, tmp = split(line, dlm)
    catch
        str = line
    finally
        return str
    end
end

line = "Hello world # my comment"
@time removecomments1(line)
@time removecomments2(line)

$>  0.016092 seconds (27.31 k allocations: 1.367 MiB)
    0.016164 seconds (31.26 k allocations: 1.548 MiB)

我的直觉(来自C++背景)告诉我,初始化两个变量应该导致速度的增加,并最小化进一步分配,因为编译器已经被告知需要第二个变量以及它的对应类型,但是这似乎不成立。为什么会这样

旁白:有没有更有效的方法来实现与这些功能相同的结果

编辑: 在Oscar Smith的一篇文章之后,将
str
初始化为type
SubString{String}
而不是
String
使分配减少了约10%:

$>  0.014811 seconds (24.29 k allocations: 1.246 MiB)
    0.015045 seconds (28.25 k allocations: 1.433 MiB)

来解释这是怎么做的,想想分裂函数会在C++中被写什么。它不会复制,而是返回一个

char*
。因此,
str::String=”“
所做的就是让Julia创建一个要忽略的额外字符串对象。

在您的示例中,需要try-catch块的唯一原因是,您正在尝试对
split
的输出进行解构,即使在输入行没有注释时
split
将返回一个单元素数组。如果您只需从
split
的输出中提取第一个元素,则可以避免try-catch构造,这将节省您的时间和内存:

julia> using BenchmarkTools

julia> removecomments3(line::String; dlm::String = "#") = first(split(line, dlm))
removecomments3 (generic function with 1 method)

julia> @btime removecomments1($line);
  198.522 ns (5 allocations: 224 bytes)

julia> @btime removecomments2($line);
  208.507 ns (6 allocations: 256 bytes)

julia> @btime removecomments3($line);
  147.001 ns (4 allocations: 192 bytes)

在对原始问题的部分回答中,预分配主要用于数组,而不是字符串或其他标量。有关何时使用预分配的更多讨论,请查看。

这两个函数中都存在此初始化,因此它肯定不会对分配产生影响吗?无论哪种方式,如果两个函数都没有使用
str::String=”“
,那么我可能应该更改代码的这一部分,但是完全删除初始化会抛出
LoadError:UndefVarError:str not defined
。相反,使用类型
子字符串{String}
初始化它会减少分配,但这对需求来说还是多余的吗?在得出任何结论之前,您应该使用BenchmarkTools并确保您不是在全局范围内进行基准测试<代码>使用基准工具@b时间removecomments1($line)@btime removecomments2($line)。我不知道在全局范围内进行基准测试会有什么不同,但下面是使用
@btime
而不是
@time
的结果:
249.887 ns(5个分配:224字节)
262.174ns(6个分配:256字节)
此外,您的
@time
调用似乎捕获了两个函数的编译时间。在使用
@time
之前,应至少运行一次函数
removecomments1(line)==removecomments2(line)
在使用
@time
之前最好先运行一行。预分配主要用于数组,而不是字符串或其他标量。据我所知,预分配字符串并没有性能或内存优势。天哪,这是一个显著的改进,尤其是当
catch
通常生效时!我以前没有遇到过
first()
,搜索引擎只显示它正在使用和更新。即使搜索也不会显示任何内容—它是什么,它做什么?
first
是一个通用函数,用于提取集合的第一个元素。它在各种包中都有扩展其功能的方法。