发明内容
根据本发明的实施例,提供了一种从fastq文件分离出样本read数据的优化方法,该方法包括:
通过两个线程并发加载包含多个样本的fastq文件,构造read数据并输出;
从所述read数据中解析出barcode对,根据所述barcode对与样本编号的对应关系识别所述read数据的所属样本,并将所述read数据***其所属样本的read缓存;
通过异步样本线程池中的异步样本线程,将所述read缓存中的read数据写入对应样本的输出fastq文件中。
进一步地,所述通过两个线程并发加载包含多个样本的fastq文件,构造read数据并输出,包括:
分配第一线程、第二线程和一个数据块队列,设置该数据块队列的最大数据项个数限制以及数据块的大小;
在所述第一线程中,向对象内存复用池发出分配内存请求,等待分配一个所述数据块大小的数据块;
在所述第一线程中,按照所述数据块的大小读取所述fastq文件,将读取到的数据放到所述分配的数据块中,判断所述数据块队列是否达到所述最大数据项个数限制,如果是,则进入等待状态,直至所述数据块队列的数据项个数小于所述最大数据项个数限制,将所述数据块***所述数据块队列的队尾;否则,将所述数据块***所述数据块队列的队尾;
继续判断所述fastq文件是否读取完毕,如果已读取完毕,则设置数据块队列结束标记,并结束第一线程;如果未读取完毕,则返回等待分配数据块,继续加载fastq文件;
在所述第二线程中,判断所述数据块队列是否为空且设置结束标记,如果所述数据块队列为空且设置结束标记,则结束第二线程;如果所述数据块队列为空且没有设置结束标记,则进入等待状态,直到所述数据块队列不为空或者被设置结束标记为止;如果所述数据块队列不为空,则从所述数据块队列的头部取出数据块,得到fastq块数据;
顺序地将所述fastq块数据进行换行解析,得到若干个read数据,并按次序逐个输出;
在所述数据块被消费后,向对象内存复用池发出释放内存请求。
进一步地,所述read数据存储于一块连续内存内,包括一个起始位置、一个结束位置和三个索引值,三个索引值设置于所述起始位置与所述结束位置之间,用于分别指向三个换行符的位置;所述三个换行符将所述起始位置与所述结束位置之间的数据分割成四行数据,其中第一行数据为信息行、第二行数据为序列行、第三行数据为注释行、第四行数据为质量行;所述换行符用于触发数据换行操作。
进一步地,所述从所述read数据中解析出barcode对,包括:
将所述read数据的第二行的前8个字符作为所述read数据的barcode;
根据所述barcode构造barcode对;
其中,在单端测序情况下,所述barcode为一个,对所述barcode进行复制,得到两个相同的barcode作为所述barcode对;
在双端测序情况下,所述barcode为两个,将两个barcode作为所述barcode对。
进一步地,所述根据所述barcode对与样本编号的对应关系识别所述read数据的所属样本,包括:
将所述read数据中的barcode进行分组,得到若干个barcode分组;每个barcode分组包含若干个互不相同的barcode,且任意barcode与其互为barcode对的barcode在同一分组中,得到barcode对与barcode分组的唯一对应关系;
定义barcode分组与样本编号的唯一对应关系,得到barcode对与样本编号的唯一对应关系;
根据barcode对与样本编号的唯一对应关系,识别出barcode对对应的read数据的所属样本。
进一步地,所述将所述read数据***其所属样本的read缓存,包括:
为每个样本分配一个read缓存;所述read缓存包括一个缓存块和一个缓存块队列;设置所述缓存块的最大存储容量;所述缓存块队列用于按顺序存储同一样本的read数据;
通过对象内存复用池为所述read缓存中的第一缓存块分配内存;
所述第一缓存块接收read数据,并判断所述read数据是否接收完毕,如果是,则将所述read缓存设置结束标记,并结束缓存;否则,将所述read数据放入第一缓存块中,并判断所述第一缓存块是否达到预设的缓存块最大存储容量,如果所述第一缓存块达到预设的缓存块最大存储容量,则将所述第一缓存块***缓存块队列的队尾,向对象内存复用池发送分配内存请求,通过对象内存复用池分配第二缓存块;如果所述第一缓存块未达到预设的缓存块最大存储容量,则继续接收read数据;
当第二缓存块被分配至所述read缓存中时,判断当前read数据是否存在未被放入缓存块的数据,如果存在,则将当前read数据中未放入缓存块的数据放入第二缓存块中,然后返回所述第一缓存块接收read数据步骤;如果不存在,则直接返回所述第一缓存块接收read数据步骤。
进一步地,还包括:
在双端测序情况下,所述read数据为两个,分别为read1和read2数据;所述缓存块为两个,用于分别存放对应的read1和read2数据;将所述两个缓存块进行关联;
当存放有read1的缓存块达到预设的缓存块最大存储容量时,将该缓存块***缓存块队列的队尾。
进一步地,还包括:
设置所述缓存块队列的最大缓存块数量;
如果将所述第一缓存块或所述存放有read1的缓存块***缓存块队列的队尾时,判断所述缓存块队列中的缓存块个数是否达到预设的最大缓存块数量,如果是,则进入等待状态,直至所述缓存块队列中的缓存块个数小于预设的最大缓存块数量为止;否则,将所述第一缓存块或所述存放有read1的缓存块***缓存块队列的队尾。
进一步地,所述通过异步样本线程池中的异步样本线程,将所述read缓存中的read数据写入对应样本的输出fastq文件中,包括:
在所述异步样本线程中,判断所述read缓存的缓存块队列是否为空且设置结束标记,如果所述缓存块队列为空且设置结束标记,则结束该异步样本线程操作;如果所述缓存块队列为空且没有设置结束标记,则进入等待状态,直到所述缓存块队列不为空或者被设置结束标记为止;如果所述缓存块队列不为空,则从所述缓存块队列头部取出一个缓存块;所述异步样本线程池包括若干个异步样本线程,且每个异步样本线程唯一对应一个read缓存,且不同异步样本线程之间相互独立;
从所述获取到的缓存块中进行反关联操作,如果得到反关联结果,则将所述获取到的缓存块与所述反关联结果分别写入对应样本的输出fastq文件中;如果未得到反关联结果,则将所述获取到的缓存块写入对应样本的输出fastq文件中;
在所述缓存块被消费后,向对象内存复用池发出释放内存请求。
进一步地,还包括:
定义对象内存复用池,为所述对象内存复用池配置分配接口和释放接口,并预设对象内存复用池的最大存储容量;所述对象内存复用池用于回收被释放的对象内存,并当待分配对象内存时,复用回收的对象内存进行分配;
当所述对象内存复用池接收到分配内存请求时,通过所述对象内存复用池的分配接口判断所述对象内存复用池是否为空,如果是,则从操作***内存分配接口分配所述分配内存请求对应的对象内存;否则从所述对象内存复用池中移出一个与所述分配内存请求对应的对象内存,根据所述分配内存请求进行分配;
当所述对象内存复用池接收到释放内存请求时,通过所述对象内存复用池的释放接口判断所述对象内存复用池是否达到所述对象内存复用池的最大存储容量,如果是,则从操作***内存释放接口释放所述释放内存请求对应的对象内存;否则将所述释放内存请求对应的对象内存放入所述对象内存复用池。
本发明通过多个线程并发加载包含多个样本的fastq文件,对多个样本的read数据进行分离,通过与样本对应的多个样本线程异步操作,将read数据输出到fastq文件中;利用并行的工作方式,多个线程同时协同作业,提升了作业效率,同时通过应用read缓存技术,大大降低了代码运行耗时,极大减少了***锁的调用次数,从而释放了大量CPU,大大减轻了操作***负载,提高了计算机性能利用率,极大地缩短了从fastq文件中分离出样本read数据的时间消耗,达到快速从fastq文件中分离出样本read数据的目的。
具体实施方式
为使本发明实施例的目的、技术方案和优点更加清楚,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有作出创造性劳动前提下所获得的全部其他实施例,都属于本发明保护的范围。
本发明中,本发明通过多个线程并发加载包含多个样本的fastq文件,对多个样本的read数据进行分离,通过与样本对应的多个样本线程异步操作,将read数据输出到fastq文件中;利用并行的工作方式,多个线程同时协同作业,提升了作业效率,同时通过应用read缓存技术,大大降低了代码运行耗时,极大减少了***锁的调用次数,从而释放了大量CPU,大大减轻了操作***负载,提高了计算机性能利用率,极大地缩短了从fastq文件中分离出样本read数据的时间消耗,达到快速从fastq文件中分离出样本read数据的目的。
图1示出了根据本发明的实施例的从fastq文件分离出样本read数据的优化方法的流程图。
该方法S100包括:
S110、通过两个线程并发加载包含多个样本的fastq文件,构造read数据并输出。
所述包含多个样本的fastq文件一般都非常大,小到几个GB,大到数十上百GB大小的都有。为了进行下一步的基因序列分析,需要从这种原始fastq文件中拆分出以样本为单位的fastq文件,即把每个样本的基因数据独立到单个fastq文件中。
作为本发明的一种实施例,本方法设计了两个线程,即第一线程和第二线程;所述第一线程用于分块读取fastq文件数据,并将读取到的数据块***数据块队列;所述第二线程用于从数据块队列中取出数据块,并对数据块中数据进行解析,得到read数据进行输出。通过所述两个线程并发加载fastq文件,构造read数据并输出的过程,如图2所示,包括:
S111、分配第一线程、第二线程和一个数据块队列,设置该数据块队列的最大数据项个数限制以及数据块的大小;所述数据块队列包括若干个数据块,且按序排列;其不为空的时候,至少有一头部数据块和尾部数据块。定义所述数据块队列的存取逻辑是通过尾部存入、通过头部取出。为所述数据块设置一固定大小,例如1MB;用于作为数据存取大小标准,使每次加载的fastq块数据大小相等。
S112、在所述第一线程中,向对象内存复用池发出分配内存请求,等待分配一个所述数据块大小的数据块;所述对象内存复用池用于回收被释放的对象内存,并当待分配对象内存时,对象内存复用池复用回收的对象内存进行分配。当所述对象内存复用池接收到分配内存请求时,如果当前对象内存复用池中有可分配的内存,则根据分配内存请求对应的待分配内存大小分配内存,并返回所述分配内存请求。如果当前对象内存复用池中没有可分配的内存,则从操作***内存分配接口分配所述分配内存请求对应的对象内存。
S113、在所述第一线程中,按照所述数据块的大小读取所述fastq文件,判断所述数据块队列是否达到所述最大数据项个数限制,如果是,则进入等待状态,直至所述数据块队列的数据项个数小于所述最大数据项个数限制,将所述数据块***所述数据块队列的队尾,此时被***的数据块即为所述数据块队列的尾部;否则,将所述数据块***所述数据块队列的队尾;继续判断所述fastq文件是否读取完毕,如果已读取完毕,则设置数据块队列结束标记,并结束第一线程;如果未读取完毕,则返回等待分配数据块,继续加载fastq文件。
S114、在所述第二线程中,判断所述数据块队列是否为空且设置结束标记,如果所述数据块队列为空且设置结束标记,则结束第二线程;如果所述数据块队列为空且没有设置结束标记,则进入等待状态,直到所述数据块队列不为空或者被设置结束标记为止;如果所述数据块队列不为空,则从所述数据块队列的头部取出数据块,得到fastq块数据。
S115、顺序地将所述fastq块数据进行换行解析,得到若干个read数据,并按次序逐个输出,在所述数据块被消费后,向对象内存复用池发出释放该数据块内存的请求。
所述第一线程与第二线程同时并行处理,即所述第一线程陆续加载所述fastq文件中的数据块到所述数据块队列中,同时所述第二线程逐个从所述数据块队列的头部依次提取数据块,并在内存中进行解析,通过解析过程,从一个个数据块中解析出read数据。利用并行的工作方式,使多线程同时协同作业,提升了作业效率,极大地减少了作业时间。
所述read数据存储于一块连续内存内,包括一个起始位置、一个结束位置和三个索引值,三个索引值设置于所述起始位置与所述结束位置之间,用于分别指向三个换行符的位置;所述三个换行符将所述起始位置与所述结束位置之间的数据分割成四行数据,其中第一行数据为信息行、第二行数据为序列行、第三行数据为注释行、第四行数据为质量行;所述换行符用于触发数据换行操作。
在本发明的一种实施例中,如图3(a)所示,为使用优化定义的read存储结构来存储一个read数据。即使用一整块连续内存来存储read的四行完整数据,给这样一块连续内存命名为READ,起始位置为0,结束位置为end。引入起始位置0和结束位置ead为了方便描述read的存取划分,实际的操作中,连续存储read四行数据的READ是一个string类型,即字符串类型,其能够得到READ的起始位置和结束位置。使用三个索引值来分别指向read数据的第一行、第二行、第三行数据的换行符的位置,例如LF_pos1、LF_pos2和LF_pos3。三个换行符将一段数据分割成4行数据,其中第一行数据为信息行,表示为READ[0,LF_pos1),表示0到字符LF_pos1之间的左闭右开区间;第二行数据为序列行,表示为READ[LF_pos1+1,LF_pos2),表示字符LF_pos1+1到字符LF_pos2之间的左闭右开区间;第三行数据为注释行,表示为READ[LF_pos2+1,LF_pos3),表示字符LF_pos2+1到字符LF_pos3之间的左闭右开区间;第四行数据为质量行,表示为READ[LF_pos3+1,end),表示字符LF_pos3+1到READ结束位置end之间的左闭右开区间。使用一整块连续内存来完整存储read的四行read数据,并将得到的每个read数据按照顺序进行输出。
在本发明的一种实施例中,如图3(b)所示,为使用传统的read存储结构来存储一个read数据。即使用四段相互不连续的内存来分别存储一个read的四行数据,其中第一行为信息行数据、第二行为基因序列数据、第三行为注释数据、第四行为序列质量数据;以此read数据内存格式顺序地逐个输出read数据。
使用传统的read存储结构,在把read数据写入存储的过程中,如果省去在内存中将四行数据重新连接到一个连续内存的过程,而采用直接单独写每行数据,那么,对于read的每一行数据就会产生一个对存储的写IO,4行数据就会有4个写IO,即一个read数据就需要4个写IO才能把数据写到存储。而在内存中将四行数据重新连接到一个连续内存之后,只需要一个写IO就能完成相同的工作。前者比后者多出了3个写IO操作。而每个写IO操作会经由操作***应用层到内核层,再到设备驱动,最后到存储硬件,这是一个很长的IO栈。相对于在内存中将四行数据重新连接到一个连续内存的操作来说,它是一个很漫长的过程。有10亿个read数据就会多出10亿*3=30亿个这样的写IO操作,这会相当慢。所以,在使用传统read存储结构时,必须要先重新连接4行数据到一个连续内存,再写到存储中。
下表为传统read存储结构与本发明优化后的read存储结构在read生命期各个阶段的操作对比:
由上表可知,在一个read的生命周期中,优化后的read存储结构比传统的存储结构少了7次数据拷贝操作,少了一次分配和释放内存的操作。将read数据放大到10亿条,就少了70亿次数据拷贝和10亿次内存分配、10亿次释放内存操作。从实际测试结果来看,模拟测试10亿条read数据逐个经历上表描述的生命周期所有阶段,传统read存储结构耗时11分钟,而优化后的read存储结构耗时4分钟。
综上,通过对read存储结构的优化,大大降低了对read数据的基本操作次数。例如,假设原始fastq文件中有10亿条read,采用优化后的read存储结构,在整个基因数据分离期间,减少了10亿*4=40亿次四行数据拆分拷贝操作,减少了10亿次四行数据重组拼接成连续内存的操作。从而释放了一大块额外的没必要的CPU和内存消耗。
S120、从所述read数据中解析出barcode对,根据所述barcode对与样本编号的对应关系识别所述read数据的所属样本,并将所述read数据***其所属样本的read缓存。
进一步地,S121、所述从所述read数据中解析出barcode对,包括:
S1211、将所述read数据的第二行的前8个字符作为所述read数据的barcode。
作为本发明的一种实施例,如图3所示:
barcode数据:READ[LF_pos1+1,LF_pos1+8];
注:是LF_pos1+1到LF_pos1+8之间的闭区间,实际上就是第二行数据的前8个字符组成的字符串。
S1212、根据所述barcode构造barcode对。
其中,在单端测序情况下,所述barcode为一个,对所述barcode进行复制,得到两个相同的barcode作为所述barcode对;
在双端测序情况下,所述barcode为两个,将两个barcode作为所述barcode对。
进一步地,S122、所述根据所述barcode对与样本编号的对应关系识别所述read数据的所属样本,如图4所示,包括:
S1221、如图5所示,将所述read数据中的barcode进行分组,得到若干个barcode分组。每个barcode分组包含若干个barcode,并且所有分组的barcode之间不重复,且任意barcode与其互为barcode对的barcode在同一分组中,这样的barcode对和所属barcode分组是多对一的关系,得到barcode对与barcode分组的唯一对应关系,即由任意这样的barcode对能定位唯一的barcode分组。
S1222、定义barcode分组与样本编号的唯一对应关系,得到barcode对与样本编号的唯一对应关系;
S1223、根据barcode对与样本编号的唯一对应关系,识别出barcode对对应的read数据的所属样本。
进一步地,S123、将所述read数据***其所属样本的read缓存,如图6所示,包括:
首先判断是单端测序还是双端测序情况,单端测序情况如下:
为每个样本分配一个read缓存;所述read缓存包括一个缓存块和一个缓存块队列;设置缓存块的最大存储容量;所述缓存块队列用于按顺序存储同一样本的read数据;
通过对象内存复用池为所述read缓存中的第一缓存块分配内存;
所述第一缓存块接收read数据,并判断所述read数据是否接收完毕,如果是,则将所述read缓存设置结束标记,并结束缓存;否则,将所述read数据放入第一缓存块中,并判断所述第一缓存块是否达到预设的缓存块最大存储容量,如果所述第一缓存块达到预设的缓存块最大存储容量,则将所述第一缓存块***缓存块队列的队尾,然后向对象内存复用池发送分配内存请求,通过对象内存复用池分配第二缓存块。
当第二缓存块被分配至所述read缓存中时,判断当前read数据是否存在未被放入缓存块的数据,如果存在,则将当前read数据中未放入缓存块的数据放入第二缓存块中,然后返回执行接收read数据步骤;如果不存在,则直接返回执行接收read数据步骤。
当存放有read1的缓存块达到预设的缓存块最大存储容量时,将该缓存块***缓存块队列的队尾。
进一步地,在双端测序情况下,所述read数据为两个,分别为read1和read2数据;所述缓存块为两个,用于分别存放对应的read1和read2数据;将所述两个缓存块进行关联。
进一步地,预先设置所述缓存块队列的最大缓存块数量;如果将所述第一缓存块***缓存块队列的队尾时,所述缓存块队列中的缓存块个数达到预设的最大缓存块数量,则进入等待状态,直至所述缓存块队列中的缓存块个数小于预设的最大缓存块数量为止。
作为本发明的一种实施例,如图7所示,通过搭建read缓存执行read数据的***和取出,所述read数据***read缓存过程包括以下步骤:
S123-1:为fastq文件的每一个输出样本分配一个独立的read缓存,所述read缓存包括一个缓存块和一个缓存块队列;所述缓存块为一固定存储容量的内存块,例如将所述缓存块容量大小为2MB。所述缓存块队列用于存储缓存块,并设置缓存块队列的最大缓存块数量,例如设置MaxCacheBlockNum为128。
S123-2:使用对象内存复用池为read缓存分配缓存块内存。
S123-3:read缓存中接收到一条对应样本的read数据,判断所述read数据是否接收完毕,如果是,则进入S123-8;否则将所述read数据追加放入缓存块,并执行步骤S123-4;所述对read数据是否获取完毕的判断,是通过识别底层文件***提供的文件结束标记来实现的,例如,当读取fastq文件结束的时候,会获取到文件***返回的EOF标记,EOF是end offile的英文简写,表示文件已经读取完毕。
S123-4:判断所述缓存块是否被填满,如果是,则执行步骤S123-5;否则,返回步骤S123-3;
S123-5:把所述缓存块***缓存块队列的队尾,在***时,判断缓存块队列已有的缓存块个数是否已达到预设的最大缓存块数量MaxCacheBlockNum,如果是,则进入“满等”状态,直至缓存块队列中有空间满足***为止;如果不是,则进入S123-6。所述“满等”状态为一种等待状态,等待原因是由于缓存块队列处于满载状态,导致待***缓存块没有空间进行***,故处于等待状态。所述缓存块队列中有空间满足***,是通过缓存块队列中已有的缓存块被取出消费后,释放队列内存空间,使处于“满等”状态的缓存块能够***到释放的内存空间。
S123-6:通过对象内存复用池分配一个新的缓存块;
S123-7:判断当前read数据是否存在未被放入缓存块的数据,如果存在,则将当前read数据中未放入缓存块的数据放入新分配的缓存块中,然后返回S123-3;如果不存在,则直接返回S123-3。
S123-8:将所述read缓存设置结束标记,并结束缓存。
如图8所示,所述从所述read缓存中取出read数据,方法包括:
判断所述read缓存的缓存块队列是否为空且设置结束标记,如果所述缓存块队列为空且设置结束标记,则结束该过程;如果所述缓存块队列为空且没有设置结束标记,则进入等待状态,直到所述缓存块队列不为空或者被设置结束标记为止;如果所述缓存块队列不为空,则从所述缓存块队列头部取出一个缓存块。所述“空等”状态是一种等待状态,等待原因是由于缓存块队列中是空队列,即无数据,导致无法从缓存块队列中取出数据,故处于等待状态。
在以具体实施例中,假设将10亿条read数据写入存储,没有使用read缓存的时候,需要10亿个写IO把所有read数据写到存储。使用read缓存后,假设一个缓存块2MB大小,可以放1.5万条read数据,那么10亿条read总共会用到大约6.6万个缓存块。写存储的时候,一个缓存块为一个写IO,即一次写2MB的数据。那么,在用了read缓存以后,10亿条read数据只需要约6.6万个写IO就把数据写完。从10亿个IO降低到6.6万个IO,降低了5个数量级。
同样的道理,原本需要调用10亿次锁和解锁操作,而现在只需要6万多次。原本各需要10亿次的入队和出队操作,现在只需要6万多次。
综上,通过设计并应用的read缓存技术,大大降低了代码运行耗时,释放了大量CPU资源,极大地减轻了操作***负载。
S130、通过异步样本线程池中的异步样本线程,将所述read缓存中的read数据写入对应样本的输出fastq文件中,如图9所示,包括:
在所述异步样本线程中,判断所述read缓存的缓存队列是否为空且设置结束标记,如果所述缓存块队列为空且设置结束标记,则结束该异步样本线程操作;如果所述缓存块队列为空且没有设置结束标记,则进入等待状态,直到所述缓存块队列不为空或者被设置结束标记为止;如果所述缓存块队列不为空,则从所述缓存块队列头部取出一个缓存块。
所述异步样本线程池包括若干个异步样本线程,且每个异步样本线程唯一对应一个read缓存,且不同异步样本线程之间相互独立;即不同的异步样本线程之间可以并行处理。
进一步地,在所述获取到的缓存块中进行反关联,所述反关联即通过获取到的缓存块中的read数据尝试关联出与其关联的read数据,这种尝试会出现两种结果,一种是能够反关联出结果,另一种是无法反关联出结果,其中反关联的结果是存有与所述获取到的read数据相关联的read数据的缓存块。如果能够反关联出结果,说明是双端测序,此时需要将所述获取到的缓存块与其反关联结果分别写入对应样本的输出fastq文件中;如果未得到反关联结果,说明是单端测序,则将所述获取到的缓存块写入对应样本的输出fastq文件中。
在将所述获取到的read数据写入对应样本的输出fastq文件中之后,还需要判断当前read缓存的缓存块队列是否为空,且存在结束标记,如果是,则结束当前异步样本线程操作,说明已经把fastq文件中的所有read数据都取出;当然,如果当前read缓存的缓存块队列为空,但不存在结束标记,则表示仅当前缓存块队列中无数据,fastq文件还有未写入的未被消费的read数据,或者当前缓存块队列不为空,则返回重新执行S130,将所述read缓存中的read数据写入对应样本的输出fastq文件中。
进一步地,如图10所示,本发明还对所有的分配和释放对象内存的地方进行了优化,具体定义了对象内存复用池。
为所述对象内存复用池配置分配接口和释放接口,并预设对象内存复用池的最大存储容量;所述对象内存复用池用于回收被释放的对象内存,并当待分配对象内存时,复用回收的对象内存进行分配。
当在分离read数据过程中会频繁用到的对象内存被释放时,对象内存复用池将这些内存回收到对象内存复用池中,而不是将这些对象内存还给操作***;当处理逻辑下次需要这些内存时,对象内存复用池直接复用之前回收的内存,将其返回给处理逻辑,而不是向操作***去申请所需内存。
所述对象内存复用池分配接口、对象内存复用池释放接口为调用函数,通过调用函数来分配和释放对象内存。
如图11所示,通过在read缓存***数据的逻辑中,复用对象内存复用池中的内存块。在read缓存移出数据逻辑中,回收之前分配的内存块。程序很快就不会再向操作***申请分配/释放缓存块的内存,完全是复用之前已经申请的固定量的内存块。
当接收到分配请求时,通过所述对象内存复用池分配接口判断所述对象内存复用池是否为空,如果是,则从操作***内存分配接口分配所述分配请求对应的对象内存;否则从所述对象内存复用池中移出一个与所述分配请求对应的对象内存,根据所述分配请求进行分配。
当接收到释放请求时,通过所述对象内存复用池释放接口判断所述对象内存复用池是否达到对象内存复用池最大存储容量,如果是,则从操作***内存释放接口释放所述释放请求对应的对象内存;否则将所述释放请求对应的对象内存放入所述对象内存复用池。
作为本发明的一种实施例,在对象内存复用池分配接口中,判断对象内存复用池是否为空,如果是,则直接从操作***内存分配接口分配该对象内存;否则从对象内存复用池中移出一个对象,作为新分配的对象内存,返回对应的分配请求。
作为本发明的一种实施例,在对象内存复用池释放接口中,判断对象内存复用池是否被填满,如果是,则直接使用操作***内存释放接口来释放该对象内存;否则将该对象内存直接放入对象内存复用池,并返回对应的释放请求。
作为本发明的一种实施例,如图12所示,在读取fastq和解析read逻辑中,即S110步骤中,在分块读取fastq线程中,复用对象内存复用池中回收的内存块。在解析read线程中,回收之前分配的内存块到对象内存复用池。以此达到良性循环,程序很快就不会再向操作***申请分配或释放有关这里的内存。
本发明通过应用基于对象内存复用池的内存复用技术,极大减少了程序从操作***分配和释放内存的次数,从而减少了大量***开销,降低了操作***负载,使程序内存使用量和CPU利用率趋于一个稳定、健康的状态。
通过将优化的read存储结构、read缓存技术以及内存复用技术联合应用到样本read数据分离过程中,极大地缩短了从fastq文件中分离出样本read数据的时间消耗。利用并行的工作方式,多个线程同时协同作用,提升了作业效率;同时采用优化定义的read存储结构,减少了每条read数据在其生命期内的字符串拷贝和重串联的次数;另外应用read缓存技术,极大减少了***锁的调用次数,以及对线程安全队列和文件***写数据接口的操作次数;应用对象内存复用池,降低了整个分离过程中向操作***申请和释放内存的请求次数,从而降低操作***负载,释放出更多的CPU资源给其他运算逻辑,达到快速从fastq文件中分离出样本read数据的目的。
下面是详细的性能对比数据,包括使用python脚本实现的工具(python分离工具)、C++版高并发分离工具(高并发分离工具)以及本发明优化后的C++版分离工具(本发明优化后的工具)的性能数据:
/>
如上表所示,采用本发明优化后的工具,相比python分离工具,平均减少94%耗时。相比高并发分离工具,平均减少60%耗时。并且原始fastq文件越大,性能优越性越明显。
本发明在每个环节都给出了单端测序和双端测序的不同处理方式,因此完美适配单端测序和双端测序,故无论是单端测序还是双端测序,本发明都能完美支持从fastq文件中快速、高效地分离出样本read数据的功能。并保证在两种模式下输出数据的正确性。
在本实施例的一些可选的实现方式中,在单端测序的情况下,S122步骤中,所述read数据为一个,通过read数据的第二行数据获取到一个barcode,对所述barcode进行复制,得到两个相同的barcode作为所述barcode对。
S123步骤中,为每个样本分配一个read缓存;所述read缓存中的缓存块队列用于按序存储同一样本的read数据;获取到一个fastq文件的一条read数据,按照所述read数据***read缓存过程,将该条read数据***对应read缓存。
S130步骤中,在异步样本线程中,从对应的read缓存的缓存块队列的头部获取一条read数据。所述异步样本线程有多个,且每个异步样本线程唯一对应一个read缓存,且不同异步样本线程之间相互独立,即不同的异步样本线程之间可以并行处理。对所述获取到的read数据进行反关联,即通过获取到的read数据尝试关联出与其关联的read数据,此时无法反关联出结果,则将所述获取到的read数据写入对应样本的输出fastq文件中。
在本实施例的一些可选的实现方式中,在双端测序的情况下,fastq文件有两个,分别为r1和r2;输出两个read,分别为read1和read2。两个fastq文件的每一对read1和read2都具有相同的ID。
S122步骤中,所述read数据为两个,通过read数据的第二行数据获取到一个barcode,将两个barcode作为所述barcode对。
S123步骤中,为每个样本分配一个read缓存;所述read缓存中的缓存块队列用于按序存储同一样本的read数据;获取r1和r2两个fastq文件的read1和read2,共两条read数据,将read2与read1进行关联,在关联之后,根据所述read数据***read缓存过程,将read1***对应read缓存。
S130步骤中,在异步样本线程中,从对应read缓存中的缓存块队列的头部获取一条read数据。所述异步样本线程有多个,且每个异步样本线程唯一对应一个read缓存,且不同异步样本线程之间相互独立,即不同的异步样本线程之间可以并行处理。对所述获取到的read数据进行反关联,此时反关联成功,反关联的结果为read2,将read数据和反关联出的read2数据写入对应样本的输出fastq文件中。
如图13所示为能够实施本发明的实施例的示例性电子设备。
设备1300包括中央处理单元(CPU)1301,其可以根据存储在只读存储器(ROM)1302中的计算机程序指令或者从存储单元1308加载到随机访问存储器(RAM)1303中的计算机程序指令,来执行各种适当的动作和处理。在RAM 1303中,还可以存储设备1300操作所需的各种程序和数据。CPU 1301、ROM 1302以及RAM 1303通过总线1304彼此相连。输入/输出(I/O)接口1305也连接至总线1304。
设备1300中的多个部件连接至I/O接口1305,包括:输入单元1306,例如键盘、鼠标等;输出单元1307,例如各种类型的显示器、扬声器等;存储单元1308,例如磁盘、光盘等;以及通信单元1309,例如网卡、调制解调器、无线通信收发机等。通信单元1309允许设备1300通过诸如因特网的计算机网络和/或各种电信网络与其他设备交换信息/数据。