我是朱莉娅语言的第一次体验,我很简单。
我需要处理大文件,其中每一行由一组制表符分隔的字符串组成。作为第一个例子,我从一个简单的计数程序开始;我设法使用@parallel和以下代码:
d = open(f)
lis = readlines(d)
ntrue = @parallel (+) for li in lis
contains(li,s)
end
println(ntrue)
close(d)
end
我将并行方法与一个3.5GB文件(超过100万行)的简单“串行”方法进行了比较。在4核Intel Xeon E5-1620,3.660GHz和32GB RAM上,我得到的是:
平行= 10.5秒;序列= 12.3秒;分配的内存= 5.2 GB;
我首先关心的是内存分配;是否有更好的方法来逐步读取文件以降低内存分配,同时保留并行处理的好处? 其次,由于与使用@parallel相关的CPU增益并不令人惊讶,我想知道它是否与特定案例本身有关,还是我天真地使用Julia的并行功能?在后一种情况下,遵循什么是正确的方法?谢谢你的帮助!
答案 0 :(得分:3)
您的程序正在将所有文件作为大量字符串一次读入内存。您可能希望尝试一个一次处理一行的串行版本(即流式传输):
const s = "needle" # it's important for this to be const
open(f) do d
ntrue = 0
for li in eachline(d)
ntrue += contains(li,s)
end
println(ntrue)
end
这避免了分配一个数组来保存所有字符串并避免一次分配所有字符串对象,允许程序通过在垃圾收集期间定期回收它来重用相同的内存。您可能想尝试这一点,看看是否能够为您充分提高性能。 s
为const
的事实非常重要,因为它允许编译器预测for循环体中的类型,如果s
可以更改值(因此类型),这是不可能的在任何时候。
如果您仍想并行处理文件,则必须在每个worker中打开该文件,并将每个worker的读取光标(使用seek
函数)推进到文件中的适当位置以开始读取线。请注意,您必须小心避免在一行中间阅读,并且您必须确保每个工作人员完成分配给它的所有行,而不是更多 - 否则您可能会错过搜索字符串的某些实例或者重复其中一些。
如果此工作负载不仅仅是一个示例,并且您实际上只想计算文件中出现某个字符串的行数,您可能只想使用grep
命令,例如从朱莉娅这样称呼它:
julia> s = "boo"
"boo"
julia> f = "/usr/share/dict/words"
"/usr/share/dict/words"
julia> parse(Int, readchomp(`grep -c -F $s $f`))
292
由于grep
命令经过数十年的精心优化,无法在文本文件中搜索符合某些模式的行,因此很难超越其性能。 [注意:如果零线可能包含您正在寻找的模式,您将需要在调用ignorestatus
函数时包装grep命令,因为grep
命令返回错误状态代码当没有比赛时。]