博客翻译-seqkit代码概述

文章翻译自Seqtk: code walkthrough

在推特上,Zach charlop-powers请我写写seqkt的代码介绍。这个博客就是简单解释下seqtk。

Seqkt是一个非常简单的项目,它分别提供了两个单个头文件的库用于哈希表和FASTA/Q解析。它只有一个".c"文件,包含了大部分独立的组件,每一个都是seqkt命令。我会从两个独立的头文件库开始

缓冲的流读取工具

在标准的C中,read()是最为基础的文件读取函数。但通常逐个字节地读取数据效率比较低,因此C标准库提供了fread系列,它调用read()一次性加载大量数据到内部缓冲中,然后按照需求返回一小块数据。这能显著地降低read()系统调用的时间花销,是大部分情况下的最优选择。

虽然fread比较高效,但是它只能处理来自于文件描述符(file descriptor, FD)的数据流,而不能处理zlib这类文件处理程序(file handler)。近期出现的编程语言大多都提供了通用的缓冲读取工具,例如Go的Bufio. 它需要用户提供一个类似read的函数,然后提供一个缓冲的单字节读取工具和一个高效的行读取工具。我们自己很难实现这些能缓冲的函数。

kseq.h内的缓冲读取程序虽然早于Go,但是基本想法是类似的。在这个文件文件中ks_getuntil()会一直读取数据,直到类似于换行符的分隔提示符。它使用memcpy()移动数据,使用单个循环测试分隔提示符。在10年前刚完成"kseq.h"的时候,zlib还不支持缓冲I/O. 使用zlib读取行非常慢。"kseq.h"对FASTA/Q解析性能上至关重要。

FASTA/Q解析器

解析器同时解析FASTQ和FASTA。它会搜寻'@'或者'>',检查这两个字符是否被读取,然后读取reads名和注释. 为了读取序列,解析器首先读取每行的第一个字符。如果是"+"或者是FASTA/Q的头信息行的提示符,解析器会停止读取;如果不是的话,它会读取剩余的行到序列缓冲中. 如果解析器在FASTA/Q头信息行停止,它会以FASTA记录返回序列,并提示头信息字符已被读取,这样解析器不需要查看下一个记录。如果解析器停在"+",它就跳过这行,会开始读取质量符号行,直到质量字符不再比序列短。解析器在下面情况下会返回一个错误,解析器到达文件的末尾,但还没有读取足够的质量信息,或者质量信息比序列长。对于一个格式存在问题的FASTA/Q文件,解析并不会引起内存出错,除非内存不够。

一个文件快速解析的小技巧:按行读取或者按快读取,而不是按字节读取。即使对于一个缓冲的读取器,使用fgetc()读取每一个字节速度很慢。实际上,为了让FASTA/Q解析能够读的更快,可以通过读取固定大小的块来实现,但是当前的解析器对于一个典型的FASTA/Q读取已经够快了。

哈希表

khash.h实现了基于2次方负载和二次探测开放寻址哈希表(open-addressing hash table)。每个桶都有2个比特的元信息表, 用于提示该桶是处于使用还是删除。查询和插入操作没有特殊之处。虽然khash的二次哈希和其他库不同,但不是重要特性。

"khash.h"和"kseq.h"非常依赖于C的宏,以至于代码不太美观。但这可能是C语言中提高类型特异代码(type-specific code)性能的唯一方法了。

Seqtk

我认为"seqtk.c"中唯一的性能相关的技巧就是将核酸映射到整型的表. 他在其他地方也经常使用。另外一个通用技巧就是isatty(), 这个函数检查数据流是否来自于标准输入。Gzip可能也用了这个函数。

"Seqkt.c"同样实现了简单的3列BED读取器和Mersenne Twister伪随机数生成器(PRNG). 其实这个PRNG是个失误,毕竟seqkt不需要一个好的PRNG。

生息的seqtk包含了大部分独立函数,每个都是seqtk的小命令。简单介绍下其中几个。"trimfq", 它使用修改的mott算法(请自行在phred.doc中搜索"Mott algorithm"). 我认为这比大多数专门的read trimmer好,因为它有更好的理论上可靠的算法。"sample"利用了reservoir sampling. 核心实现只接受两行. 实际上你可以用awk实现

cat file.txt | awk -v k=10 '{y=x++

最后,这是我第一次在博客上介绍代码,我不太清楚这是否有用,或许这也不算是代码概述(code walkthrough)吧。

你可能感兴趣的:(博客翻译-seqkit代码概述)