gpt4 book ai didi

c++ - (Qt with C++)Reading a file(~25Mb) and comparison strings turned be slower than python

转载 作者:行者123 更新时间:2023-11-28 01:25:21 25 4
gpt4 key购买 nike

我有两个文件,“测试”和“示例”。每个文件都包含“rs-numbers”,后跟“genotypes”。

测试文件比示例文件小。只有大约 150 个 rs-numbers+它们的基因型。

然而,示例文件包含超过 900k 个 rs-numbers+它们的基因型。

readTest() 打开“test.tsv”,逐行读取文件,并返回一个元组 vector 。元组包含(rs-number,geno type)。

analyze() 从 readTest() 中获取结果,打开示例文件,逐行读取文件,然后进行比较。

示例文件中的示例:

rs12124811\t1\t776546\tAA\r\n

rs11240777\t1\t798959\tGG\r\n

rs12124811 和 rs11240777 是 rs 编号。 AA和GG是它们的基因型。

运行时间为 n*m。在我的这个程序的 c++ 版本中,它需要 30 秒,而 python 版本只需要 15 秒和 5 秒的多处理。

vector<tuple<QString, QString>> readTest(string test){
// readTest can be done instantly
return tar_gene;
}

// tar_gene is the result from readTest()
// now call analyze. it reads through the sample.txt by line and does
// comparison.
QString analyze(string sample_name,
vector<tuple<QString, QString>> tar_gene
){

QString data_matches;

QFile file(QString::fromStdString(sample_name));
file.open(QIODevice::ReadOnly);
//skip first 20 lines
for(int i= 0; i < 20; i++){
file.readLine();
}

while(!file.atEnd()){ // O(m)
const QByteArray line = file.readLine();
const QList<QByteArray> tokens = line.split('\t');
// tar_gene is the result from readTest()
for (auto i: tar_gene){ // O(n*m)
// check if two rs-numbers are matched
if (get<0>(i) == tokens[0]){
QString i_rs = get<0>(i);
QString i_geno = get<1>(i);
QByteArray cur_geno = tokens[3].split('\r')[0];
// check if their genotypes are matched
if(cur_geno.length() == 2){
if (i_geno == cur_geno.at(0) || i_geno == cur_geno.at(1)){
data_matches += i_rs + '-' + i_geno + '\n';
break; // rs-numbers are unique. we can safely break
// the for loop
}
}
// check if their genotypes are matched
else if (cur_geno.length() == 1) {
if (i_geno == cur_geno.at(0)){
data_matches += i_rs + '-' + i_geno + '\n';
break; // rs-numbers are unique. we can safely break
// the for loop
}
}
}
}
}
return data_matches; // QString data_matches will be used in main() and
// printed out in text browser
}

这里是完整的源代码

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}

QString analyze(string sample_name,
vector<tuple<QString, QString>> tar_gene,
int start, int end){

QString rs_matches, data_matches;

QFile file(QString::fromStdString(sample_name));
file.open(QIODevice::ReadOnly);
//skip first 20 lines
for(int i= 0; i < 20; i++){
file.readLine();
}

while(!file.atEnd()){
const QByteArray line = file.readLine();
const QList<QByteArray> tokens = line.split('\t');
for (auto i: tar_gene){
if (get<0>(i) == tokens[0]){
QString i_rs = get<0>(i);
QString i_geno = get<1>(i);
QByteArray cur_geno = tokens[3].split('\r')[0];
if(cur_geno.length() == 2){
if (i_geno == cur_geno.at(0) || i_geno == cur_geno.at(1)){
data_matches += i_rs + '-' + i_geno + '\n';
break;
}
}
else if (cur_geno.length() == 1) {
if (i_geno == cur_geno.at(0)){
data_matches += i_rs + '-' + i_geno + '\n';
break;
}
}
}
}
}
return data_matches;
}

vector<tuple<QString, QString>> readTest(string test){
vector<tuple<QString, QString>> tar_gene;
QFile file(QString::fromStdString(test));
file.open(QIODevice::ReadOnly);
file.readLine(); // skip first line
while(!file.atEnd()){
QString line = file.readLine();
QStringList templist;
templist.append(line.split('\t')[20].split('-'));
tar_gene.push_back(make_tuple(templist.at(0),
templist.at(1)));
}
return tar_gene;
}

void MainWindow::on_pushButton_analyze_clicked()
{
if(ui->comboBox_sample->currentIndex() == 0){
ui->textBrowser_rs->setText("Select a sample.");
return;
}
if(ui->comboBox_test->currentIndex() == 0){
ui->textBrowser_rs->setText("Select a test.");
return;
}
string sample = (ui->comboBox_sample->currentText().toStdString()) + ".txt";
string test = ui->comboBox_test->currentText().toStdString() + ".tsv";

vector<tuple<QString, QString>> tar_gene;

QFile file_test(QString::fromStdString(test));
if (!file_test.exists()) {
ui->textBrowser_rs->setText("The test file doesn't exist.");
return;
}

tar_gene = readTest(test);

QFile file_sample(QString::fromStdString(sample));
if (!file_sample.exists()) {
ui->textBrowser_rs->setText("The sample file doesn't exist.");
return;
}
clock_t t1,t2;

t1=clock();
QString result = analyze(sample, tar_gene, 0, 0);
t2=clock();
float diff ((float)t2-(float)t1);

float seconds = diff / CLOCKS_PER_SEC;
qDebug() << seconds;
ui->textBrowser_rsgeno->setText(result);
}

如何让它运行得更快?我用 C++ 重新制作了我的程序,因为我希望看到比 Python 版本更好的性能!


在@Felix 的帮助下,我的程序现在需要 15 秒。稍后我会尝试多线程。

这里是源数据文件的例子:

(测试.tsv)rs17760268-Crs10439884-Ars4911642-Crs157640-G... 和更多。它们没有排序。

(示例.txt)rs12124811\t1\t776546\tAA\r\nrs11240777\t1\t798959\tGG\r\n... 和更多。它们没有排序。

对更好的数据结构或算法有什么建议吗?

最佳答案

实际上,您可以做很多事情来优化此代码。

  1. 确保您使用的 Qt 针对速度而非大小进行了编译优化
  2. 以 Release模式构建您的应用程序。确保设置正确的编译器和链接器标志以优化速度,而不是大小
  3. 尝试更多地使用引用资料。这避免了不必要的复制操作。例如,使用 for(const auto &i : tar_gene)。还有更多的例子。基本上,尽量避免任何不是引用的东西。这也意味着尽可能使用 std::move 和右值引用。
  4. 启用 QStringBuilder。它将优化字符串的连接。为此,请将 DEFINES += QT_USE_QSTRINGBUILDER 添加到您的 pro 文件中。
  5. 对整个代码使用QStringQByteArray。混合它们意味着 Qt 必须在每次比较它们时转换它们。

这些只是您可以做的最基本和最简单的事情。尝试一下,看看您能获得多少速度。如果仍然不够,您可以尝试进一步优化您在此处实现的数学算法,或者更深入地研究 C/C++ 以学习所有可以提高速度的小技巧。

编辑:您还可以尝试通过将代码拆分到多个线程来提高速度。手动执行此操作不是一个好主意 - 看看 QtConcurrent如果您对此感兴趣。

关于c++ - (Qt with C++)Reading a file(~25Mb) and comparison strings turned be slower than python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54118145/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com