关于julia中的try catch或类型转换性能:尝试捕获或在julia中键入转换性能 – (Julia 73秒,Python 0.5秒)

try catch or type conversion performance in julia - (Julia 73 seconds, Python 0.5 seconds)

我一直在和Julia玩,因为它在语法上类似于python(我喜欢它),但声称速度更快。但是,我尝试用类似于python中的脚本来测试使用此函数的文本文件中的数值:

1
2
3
4
5
6
7
8
function isFloat(s)
    try:
        float64(s)
        return true
    catch:
        return false
    end
end

出于某种原因,这需要大量的时间来创建一个文本文件,其中包含相当数量的文本行(~500000)。为什么会这样?有更好的方法吗?从这一点上,我可以理解该语言的什么一般特征来应用于其他语言?

以下是我用时间运行的两个精确脚本供参考:

Python:~0.5秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def is_number(s):
    try:
        np.float64(s)
        return True
    except ValueError:
        return False

start = time.time()
file_data = open('SMW100.asc').readlines()
file_data = map(lambda line: line.rstrip('
').replace(',',' ').split(), file_data)

bools = [(all(map(is_number, x)), x) for x in file_data]
print time.time() - start

茱莉亚:~73.5秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
start = time()
function isFloat(s)
    try:
        float64(s)
        return true
    catch:
        return false
    end
end
x = map(x-> split(replace(x,",","")), open(readlines,"SMW100.asc"))

u = [(all(map(isFloat, i)), i) for i in x]

print(start - time())


还要注意,您可以使用标准库中的float64-is valid函数来(a)检查字符串是否是有效的浮点值,(b)返回该值。

还要注意,在你的isFloat代码中,trycatch之后的冒号(:)在julia中是错误的(这是一个pythonism)。

更快的代码版本应该是:

1
2
3
4
5
6
7
8
9
const isFloat2_out = [1.0]
isFloat2(s::String) = float64_isvalid(s, isFloat2_out)

function foo(L)
    x = split(L,",")
    (all(isFloat2, x), x)
end

u = map(foo, open(readlines,"SMW100.asc"))

在我的机器上,对于一个包含100000行和10列数据(其中50%是有效数字)的示例文件,您的python代码需要4.21秒,而我的julia代码需要2.45秒。


这是一个有趣的性能问题,可能值得提交给Julia用户以获得比可能提供的更集中的反馈。乍一看,我认为您遇到了一些问题,因为(1)开始时Try/Catch的速度稍慢,然后(2)您使用Try/Catch的环境中存在大量类型不确定性,因为许多函数调用不返回稳定的类型。结果,Julia解释器花费大量的时间试图找出对象的类型,而不是进行计算。很难确切地知道大瓶颈在哪里,因为你做了很多在朱莉娅身上不太习惯的事情。而且,您似乎是在全局范围内进行计算,由于额外的类型不确定性,Julia的编译器无法执行许多有意义的优化。


在控制流中使用异常是好是坏这一问题上,python有点模棱两可。看到python使用异常处理被认为是坏的控制流吗?但是,即使在Python中,一致认为用户代码也不应该使用控制流的异常(尽管出于某种原因,允许生成器这样做)。因此,基本上,简单的答案是您不应该这样做——异常情况是针对异常情况的,而不是针对控制流的。这就是为什么茱莉亚的Try/Catch构造速度几乎为零的原因——首先,你不应该像那样使用它。当然,我们可能会在某个时候加快速度。

也就是说,作为Julia标准库的设计者,我们有责任确保我们提供的API不会强迫您使用控制流的异常。在这种情况下,您需要一个函数,它允许您尝试将某个内容解析为浮点值,并指示这是否可能––不是通过引发异常,而是通过返回正常值。我们不提供这样的API,所以这最终是Julia标准库的一个缺陷——正如它现在存在的那样。我打开了一个讨论这个API设计问题的问题:https://github.com/julialang/julian/issues/5704。我们来看看结果如何。