Julia中对打开文件数目的限制


Julia语言中出现无法操作文件错误情形以及可能的解决的方式。

这段时间,由于之前Python程序在对大区域问题的处理中实在是慢的不可接受, 所以重新看了一下Julia语言,发现大版本已经更新到1了,于是从新在Julia下实现了处理程序。 Python与Julia还是比较相似的,所以整个过程还算顺利。

不过在具体运行的过程中,程序经常在运行了一段时间后出问题。 虽然具体错误不同,但是错误的类型是基本一致的,主要就是无法打开文件。

LoadError: SystemError: unable to read directory /home/mount/case/data/: Too many open files

这个程序的主要运行过程就是遍历文件夹中的所有文件,然后依次处理。 经过初步的分析后发现,基本上都是处理到1000个左右后报错退出。 由于Python程序完全没有这个问题, 所以感觉上问题可能是Julia有文件打开数目限制或者Julia的GC没有python的有效率。

第一次尝试就是手动关闭文件调用。 我的程序主要的文件操作是对SQLite文件,由于SQLite.jl的说明里面说

The SQLite.DB will automatically closed/shutdown when it goes out of scope (i.e. the end of the Julia session, end of a function call wherein it was created, etc.)

而且SQLite的关闭函数是 _close,应该是不希望直接调用,所以开始的时候没有使用。 在添加 _close 之后,程序突破了1000文件的的禁锢。 但是在继续运行的时候,发现是可以处理超过1000个了,但是到2000个的时候,又出文件无法打开了。

这个时候,必须找到都打开了哪些文件了。 在Linux下可以参照 https://www.cyberciti.biz/tips/linux-procfs-file-descriptors.html

运行ls -al /proc/xxxxx/fd (xxxx 为Julia进程pid), 发现大量的db文件,而且都是处理后的db。 由于我的程序运行的逻辑是读取每个原始db文件,然后新建一个db文件,并存入处理后的数据, 所以一次会打开两个文件。 但是显然_close之后只关闭了原始db文件,而新建的db文件,即使我已经显式指定关闭,但是还是不行。

到这里感觉就是GC的问题了,添加一个手动GC的语句, 也即在循环上加上了 if ii%100=0 GC.gc() end。 然后持续监控打开文件数目(ls -al /proc/xxxxx/fd |grep db | wc) 发现基本db文件的数目一直保持在100以内了。 对接近3000个数据文件的处理也不在出现问题。

在处理完以上的问题后,从头开始计算另一个事件的时候, 发现在Julia调用另一个C++程序的时候又出问题了。 这个C++程序同样遍历文件夹内所有文件,然后处理。 这一次的特征更加明显,每到255或者256个文件的时候,直接报错,而且直接是SQLite的错误。

SQL error: unable to open database file
SQL error: unable to open database file
SQL error: unable to open database file
create data table SQL error: unable to open database file

有了上面的经验,迅速找到SQLite调用语句,发现在SQLite中有sqlite3_close_v2(db);。 Macos下使用 lsof -c rinex3_test 查看程序打开的文件,发现大量db文件。 所以问题还是在没有关闭文件上, 查看了一下说明(http://www.sqlite.org/c3ref/close.html),应该要把 prepared statements 结束(sqlite3_finalize)。 添加后,再次运行发现不存在256的退出问题了。

最后回想程序在之前的运行中,特指Python版本的程序中,应该也存在这些问题, 不过由于Python容错更高(?)一直没有频繁出现也就没有寻找并解决这些Bugs。 而Julia不知是本身有限制,还是没有打磨完整,遇到错误直接退出, 反而凸显出这些问题了。