C++加速解析大字符串的多个子()或等效函数调用

C++ Speeding up multiple substr() or equivalent function calls for parsing of a large string

本文关键字:函数调用 加速 字符串 C++      更新时间:2023-10-16

我正在尝试解析从文件加载到内存中的大字符串。我正在用一个可变长度的滑动窗口解析DNA序列(存储为字符串)。问题是字符串太大了,需要很长时间才能遍历它们。我不知道这是否可能,但有可能以某种方式加快速度吗?

我的意思是,我预计I/O将主导我的应用程序,所以我将逐行读取改为立即将整个文件读取到内存中,但在测试我的代码后,我发现它大部分时间都在这样的循环中:

size_t currentCharNumber = 0;
int16_t windowSize = 50;
//seq is a string of length 249250621
while(seq.length() - currentLinePos < windowSize)
{
   string temp = seq.substr(currentLinePos, windowSize);
   //do stuff to temp
   ++currentLinePos;
}

将序列从文件加载到内存只需要几秒钟,但解析序列需要大约30分钟(即使在注释掉substr()调用下面的处理之后)。是我遗漏了一些增加了大量开销的东西,还是可能是由于我的数据大小?

提到我可以忽略具有ATCG以外字符的子字符串,这会有帮助吗?我的意思是,我在代码中进行过滤,但只有在从substr中获得字符串之后。

这是我第一次发帖,我的C++有点生疏。如有任何反馈,我们将不胜感激。

您可能需要考虑从使用string来固定滑动窗口切换到使用std::deque<char>deque类型针对在两端插入和删除值进行了优化,因此在这里是一个很好的候选者。您可以从将前50个字符加载到deque开始,然后可以这样调整循环:

/* Initialize the window to the first windowSize characters. */
std::deque<char> window(seq.begin(), seq.begin() + windowSize);
/* Repeatedly process each window. */
for (size_t i = windowSize; i < seq.length(); ++i) {
    /* Do something to window */
    /* Drop the first character from the window, then add the next character
     * of the sequence.
     */
    window.pop_front();
    window.push_back(seq[i]);     
}

这使得构建每个窗口的时间为O(1),而不是O(k),其中k是窗口中的字符数。这可能会显著减少运行时间,因为窗口中的字符数量相当大。

希望这能有所帮助!

您可以通过将两个指针分隔到原始字符串中来定义滑动窗口,并使用它,而不是将整个范围复制到一个单独的字符串中。如果std::string构造是开销,请避免它。

您也可以每次重复使用相同的std::string实例(假设窗口大小是恒定的),但它仍然会花费您一次复制操作(不过,对于较小的窗口/长度比,这可能可以忽略不计)。

std::string::substr的调用可能会导致过多的动态内存分配,并且至少会复制缓冲区。通常,您可以通过更改算法以使用字符串定义迭代器来减少对substr的需求。