You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用线程后程序仍较慢?CSV数据处理性能优化问询

CSV新冠疫情数据处理性能优化问题

我正在完成一个涉及HashTable的作业,处理WHO网站的300K+行新冠疫情.csv数据时遇到性能瓶颈。原单线程读取处理耗时约2分钟,改用线程优化后(线程数设为std::thread::hardware_concurrency(),我的2021款MacBook Pro M2上是64),耗时降到6秒,但仍想进一步提升性能。

我不想硬编码线程数,因为最终助教运行的设备配置未知。试过增加线程数,但速度没有提升。


现有代码

分块处理函数

void process_chunk(std::vector<std::string> chunk, CovidDB* db, std::mutex* mtx) {
    std::string latest_date_str = "01/01/00"; // initialize to an old date
    std::tm latest_date = {};
    std::istringstream iss(latest_date_str);
    iss >> std::get_time(&latest_date, "%m/%d/%y");
    for (auto line : chunk) {
        std::stringstream ss(line);
        std::string country, date_str, cases_str, deaths_str;
        std::getline(ss, date_str, ',');
        std::getline(ss, country, ',');
        std::getline(ss, cases_str, ',');
        std::getline(ss, deaths_str, ',');

        int cases = std::stoi(cases_str);
        int deaths = std::stoi(deaths_str);

        std::tm entry_date = {};
        std::istringstream iss2(date_str);
        iss2 >> std::get_time(&entry_date, "%m/%d/%y");

        if (mktime(&entry_date) > mktime(&latest_date)) {
            latest_date_str = date_str;
            latest_date = entry_date;
        } 

        DataEntry* entry = new DataEntry();
        entry->set_country(country);
        entry->set_date(latest_date_str);
        entry->set_c_cases(cases);
        entry->set_c_deaths(deaths);

        std::lock_guard<std::mutex> lock(*mtx);
        db->add(entry);
    }
}

数据加载函数

void CovidDB::add_covid_data(std::string const COVID_FILE) {
    std::ifstream file(COVID_FILE);

    if (!file) {
        std::cout << "
[File ERROR]
 " << COVID_FILE << std::endl;
        std::exit(EXIT_FAILURE);
    }

    std::string line;
    std::getline(file, line); // skip header line

    std::string latest_date_str = "01/01/00"; // initialize to an old date
    std::tm latest_date = {};
    std::istringstream iss(latest_date_str);
    iss >> std::get_time(&latest_date, "%m/%d/%y");

    const int num_threads = std::thread::hardware_concurrency();
    std::vector<std::vector<std::string>> chunks(num_threads);

    int i = 0;
    while (std::getline(file, line)) {
        chunks[i % num_threads].push_back(line);
        i++;
    }

    file.close();

    std::vector<std::thread> threads;
    std::mutex mtx;

    for (auto chunk : chunks) {
        threads.emplace_back(process_chunk, chunk, this, &mtx);
    }

    for (auto& thread : threads) {
        thread.join();
    }
}

Makefile

CXX = g++
CXXFLAGS = -std=c++11 -pthread -g -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -Wno-return-type -Wno-unused-variable
LDFLAGS = -pthread

all: main

main: CovidDB.o main.o
    $(CXX) $(CXXFLAGS) -o $@ $^

CovidDB.o: CovidDB.cpp CovidDB.h
    $(CXX) $(CXXFLAGS) -c $<

main.o: main.cpp CovidDB.h
    $(CXX) $(CXXFLAGS) -c $<

clean:
    rm -f main *.o

性能优化方案

1. 解决全局锁竞争问题

当前每个循环迭代都加锁调用db->add(entry),线程几乎都在等待锁,完全抵消了多线程的优势。优化方式:

  • 每个线程先构建局部数据结构(比如局部HashTable),处理完整个chunk后,再一次性批量写入全局CovidDB,此时只需要加一次锁。
  • 或者给CovidDB做分片锁:按country的哈希值分配不同的锁,减少锁竞争范围。

2. 合理设置线程数

std::thread::hardware_concurrency()返回的是逻辑核心数(M2为64),但过多线程会导致上下文切换开销剧增。建议:

  • 线程数设为物理核心数的2-4倍,可以用std::thread::hardware_concurrency() / 2估算物理核心数(大部分现代CPU超线程为2倍)。
  • 不需要硬编码,通过逻辑核心数的比例动态计算。

3. 减少字符串与日期处理开销

  • 复用std::stringstream和std::istringstream对象,避免频繁构造析构。
  • 将日期转换为整数(比如YYYYMMDD格式),直接用整数对比替代mktime()调用,大幅减少耗时。

4. 内存分配优化

  • 避免循环内频繁new DataEntry(),改用线程局部的std::vector<DataEntry>存储数据,处理完后转移所有权到全局DB。
  • 传递chunk时用std::move避免拷贝:将process_chunk的参数改为std::vector<std::string>&& chunk,创建线程时传入std::move(chunk)。

5. 文件读取优化

  • 一次性读取整个文件到内存再分割成chunk,减少IO系统调用次数。
  • 添加std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr);关闭同步,加速文件读取。

6. 编译优化

去掉调试选项-g,添加-O3优化级别,提升运行速度:

CXX = g++
CXXFLAGS = -std=c++17 -pthread -O3 -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -Wno-return-type -Wno-unused-variable
LDFLAGS = -pthread

内容的提问来源于stack exchange,提问作者user21856923

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:37:54