Avoiding memory bloat when reading

当 Table代码随机访问大的 archive时,可能发生内存膨胀(memory bloat)。这可能发生在RandomAccessTableReader<SomeHolder>的一个对象读取 archive时。Table代码在编写时被优先保证正确性,所以当以随机访问方式读 archive时,除非你给定了额外的信息(也是下面要讨论的),它不会丢掉它已经读过的对象,以防后面还会被再次访问。一个明显的问题是:为什么 Table代码不直接跟踪对象在文件中的起点,然后用 fseek()定位到那个位置呢?我们还没实现这一点,原因如下:你能用 fseek()的前提是被读的 archive是一个实际的文件(i.e.不是一个管道命令或标准输入)。如果 archive是一个磁盘上的实际文件,你在写它时很可能已经附含了 scp文件来标识偏置信息(用“ark,scp”前缀,见 Writing an archive and a script file simutaneously),并提供了这个 scp文件给程序来帮助读 archive。这几乎和直接读 archive一样高效,因为代码读入 scp文件后可以避免重复打开不需要的文件或不必要地调用 fseek()。所以把 archive文件看做一个特列并在文件中附加偏置信息并不会解决这一问题。

当以随机访问模式读 archive时会产生两个独立的问题,如果你用“ark:”前缀并不提供额外选项,它们可能同时产生。

  • 如果你请求一个不存在 archive中的 key时,读代码会被强制读到文档结束来确保它真的不存在。
  • 每次代码读一个对象时,它都被强制保留在内存中以防后面还会被请求到。

关于第一个问题(要一直读到文件末尾),避免它的方式是确保 archive按照 key排序(按照通用的“C”字符串顺序排序,即“sort”代码所用的那样,如果指定“export LC_ALL=C”)。你可以在读 archives时用“s”选项来实现:例如,rspecifier“ark,s:-”指示代码读标准输入时将其看做 archive并期望它是有序的。Table代码会检测你声明的是否是真,如果不是将会停止运行。当然,你应该设置你的脚本,保证 archives实际上是按 key排序好的(通常这在特征提取阶段就会被完成)。

关于第二个问题(强制在内存中保留已经读过的内容),有两个解决方案。

  • 第一个解决方案,是一个不太稳定的方案,即提供“once”选项;例如,rspecifier“ark,o:-”从标准输入中读数据并认为每个对象你只会请求一次。为了确保这一点你必须知道在处理问题的程序是如何工作的,而且你应该知道提供给程序的其他 Table不包含重复的 keys(是的,Tables可以包含重复的 keys只要它是被顺序访问的)

如果你提供“o”选项,Table可以再访问对象后释放它们。然而,这只在你的 archives完全同步对齐,且不存在空隙(gaps)或缺少元素时才能有效。例如,假设你执行以下命令:

some-program ark:somedir/some.ark "ark,o:some command|"

程序“some-program”首先会顺序遍历 archive“somedir/some.ark”,然后对于它遇到的每一个 key,随机访问第二个 archive。注意命令行中变量的顺序不是任意的:我们采用了这样的惯例,被顺序访问的 rspecifiers出现在被随机访问的 rspecifiers之前。

假设两个 archives大部分都对齐了,但是有很多空隙(i.e.丢失的 keys,e.g.由于特征提取、数据对齐等产生的错误)每当第一个 archive中有空隙时,程序就需要缓存第二个 archive中的相关对象,因为它不知道它们在后面会不会被访问(它只能丢弃已经读过了的对象)。第二个 archive中有空隙时,问题会更严重,因为哪怕只有一个元素有空隙,当程序请求这 个key时,它就要一直读到第二个 archive的末尾来寻找,并且缓存这一过程中遇到的所有对象。

  • 第二个解决方案比较鲁棒,即用“called-sorted”(cs)选项。这确保对象会被顺序地请求,同样地,这也需要知道程序是如何工作的,而且所有被顺序访问的 archives都是排好序的。“cs”选项一般和“s”选项一起用时效用最高。假设我们执行以下命令:

some-program ark:somedir/some.ark "ark,s,cs:some command|"

我们假设两个 archives都是排好序的,程序会顺序访问第一个 archive,随机访问第二个 archive。这样就对空隙鲁棒了。想象第一个 archive中存在一个空隙(e.g.它的 keys是001, 002, 003, 081, 082, ...)。当在第二个 archive,搜索完 key 003后搜索 key 081时,代码会遇到 keys 004, 005, ...,但是它能忽视这些对象,因为它知道081之前的 key都不会再被请求(感谢“cs”选项)。如果第二个 archive中存在空隙,因为是排好序的,它能避免要搜索到文件末尾(这是“s”选项的作用)

results matching ""

    No results matching ""