使用线程后程序仍较慢?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
相关产品推荐
相关产品推荐

