rusbaron
@rusbaron
Не стыдно не знать, стыдно не интересоваться

Как правильно параллельно обрабатывать файлы на c++?

Доброго времени суток!
Дали тестовое задание, на входе получаю папку с файлами.Необходимо прочитать все текстовые файлы в папке(в файлах записано целое число),просуммировать.Выводить в stdout название файла и его содержимое по мере прочтения,в конце вывести общую сумму.
Считывать файлы параллельно,после прочтения файла поток усыпить на 1 секунду.
Дело в том что с параллельными вычислениями на с++ я ещё не работал. В результате смог написать вот это:
#include "boost/filesystem.hpp" ///For reading directory
#include "boost/lexical_cast.hpp" ///For converting and checking data in file
#include <iostream> ///Cout
#include <fstream> ///Open file
#include <atomic> ///For total sum
#include <thread> ///Parallel working


using namespace std;
using namespace boost::filesystem;


atomic_int TotalSum;
/*
* Func for reading and checking file content.Return readed value.
*/
void ReadFile(path InputFileWithPath)
{
	using boost::lexical_cast;
	using boost::bad_lexical_cast;
	int Answer = 0;
	std::ifstream InputFile(InputFileWithPath.string());
	string tmpString;
	if(InputFile.is_open())
	{
		while(!InputFile.eof())
		{
			getline(InputFile, tmpString);
		}
		
	}
	try {
		Answer=lexical_cast<int>(tmpString);
		cout << InputFileWithPath.filename() << ": " << Answer << endl;
		TotalSum += Answer;
		this_thread::sleep_for(chrono::seconds(1));
	}
	catch (const bad_lexical_cast &) {
		///Do nothing
	}
}

int main(int argc, char *argv[])
{
	TotalSum = 0;

	path InputPath(argv[1]);

	directory_iterator EndIterator;

	for(directory_iterator FileIterator(InputPath);FileIterator!=EndIterator;++FileIterator)
	{
		if(is_regular_file(FileIterator->path()))
		{
			thread ReadFileThread(ReadFile, move(FileIterator->path()));
			ReadFileThread.detach();
		}
	}
	cout << "Final sum: " << TotalSum << endl;

	return 0;
}

Но судя по результату работы вижу что неправильно сделал. Ибо если делать join потока,то всё чтение будет проходить как в последовательном режиме.При detach как написано в коде выше,нет смысла усыплять поток на 1 секунду.Как правильно можно обработать файлы параллельно?
  • Вопрос задан
  • 1051 просмотр
Решения вопроса 2
@nirvimel
Завести vector<thread>.
Сначала в цикле породить все потоки и сохранить в вектор.
Потом другим циклом пройтись по всем и сделать join каждому.

P.S.: В реальном коде с точки зрения производительности лучше проверять is_regular_file тоже внутри потока. И нет смысла в цикле читать из файла все строки ради значения последней (может лучше было бы - первой) строки. Что если попадется многогигабайтный файл?
Ответ написан
@syrov
пишу программы до 99 строк
Еще можно посмотреть в сторону OpenMP.
И тут есть 2 места для параллелизма: чтение файлов и суммирование. Суммирование тоже можно выполнять параллельно:

#pragma omp parallel for reduction (+:sum)
for (i=0;i < n;i++)
  sum=sum+a[i];


И еще вывод в cout нужно наверное синхронизировать.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
mayton2019
@mayton2019
Bigdata Engineer
Это видимо учебная задача. Практического смысла параллелизма здесь мало.

Обычная дисковая подсистема на домашнем ноутбуке состоит из 1 HDD/SDD. И он не параллелится. Тоесть это такое жлобское устройство которое в 1 момент времени может обслуживать чтение и запись 1 блока файловой системы (или сектора или кластера неважно). Поэтому параллелизм толком ничего не дает. Однако если у вас какие-то RAID массивы или сеть хранения данных то она может обеспечить такие действия.

Что еще в задаче плохо.
while(!InputFile.eof())
    {
      getline(InputFile, tmpString);
    }

Непонятно что здесь происходит? Перемотка в конец файла? Почему так дорого? Почему мы должны каждый раз получать строки? Ведь нам нужна только последняя? Может надо было взять первую? Вобщем непонятно.

Вот если-бы автор решал задачи наподобие map-reduce где работают с большими файлами тогда параллелизм был бы понятен. Там чтение блока файла чередуется в вычислениями.

Здесь вычисления - мелкие. И большая часть процессорного времени зря сгорит в старт-стопах потоков и в финальном join потоков (которые я кстати не вижу).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы