I have made a non-threaded version of counting words. The result was unexpected the non-threaded version was faster than threaded-parallel version.
Non-threaded version:
//
// program name: WordCounter
//
// usage: C:\>WordCounter.exe test.txt test1.txt
//
#include <future>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <exception>
#include "Profiler.h"
using Words = std::unordered_map < std::string, std::size_t >;
Words loadFromFile(const std::string& fileName)
{
std::ifstream file(fileName);
if (!file)
{
throw "Can't open the file " + fileName;
}
Words words;
for (std::string word; file >> word;)
{
++words[word];
}
return words;
}
template<typename T>
void showResult(T begin, T end)
{
std::vector<T> words;
words.reserve(std::distance(begin, end));
for (auto i = begin; i != end; ++i)
{
words.push_back(i);
}
std::sort(words.begin(), words.end(),
[](const T& it1, const T& it2)
{
return it1->second > it2->second;
});
int x = 0;
for (const auto& i : words)
{
if (x++ == 0)
{
std::cout << "\nThe most repeated element is: " << i->first << "\n\n";
std::cout << " Word\tRepeated Times";
std::cout << '\n' << std::setfill('-') << std::setw(28) << '\n';
}
std::printf(" %-10s%5d\n", i->first.c_str(), i->second);
}
}
int main(int argc, char *argv[])
{
profiler.begin("test");
std::vector<Words> resources;
resources.reserve(argc - 1);
for (int i = 1; i < argc; ++i)
{
resources.push_back(loadFromFile(argv[i]));
}
Words words;
for (auto& i : resources)
{
Words result = i;
for (auto& j : result)
{
words[j.first] += j.second;
}
}
showResult(words.begin(), words.end());
profiler.end("test");
std::cout << '\n' << profiler.data("test") << " seconds\n";
}
Threaded-parallel version:
//
// program name: WordCounter
//
// usage: C:\>WordCounter.exe test.txt test1.txt
//
#include <future>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <exception>
#include "Profiler.h"
using Words = std::unordered_map < std::string, std::size_t >;
Words loadFromFile(const std::string& fileName)
{
std::ifstream file(fileName);
if (!file)
{
throw "Can't open the file " + fileName;
}
Words words;
for (std::string word; file >> word;)
{
++words[word];
}
return words;
}
template<typename T>
void showResult(T begin, T end)
{
std::vector<T> words;
words.reserve(std::distance(begin, end));
for (auto i = begin; i != end; ++i)
{
words.push_back(i);
}
std::sort(words.begin(), words.end(),
[](const T& it1, const T& it2)
{
return it1->second > it2->second;
});
int x = 0;
for (const auto& i : words)
{
if (x++ == 0)
{
std::cout << "\nThe first most repeated element is: " << i->first << "\n\n";
std::cout << " Word\tRepeated Times";
std::cout << '\n' << std::setfill('-') << std::setw(28) << '\n';
}
std::printf(" %-10s%5d\n", i->first.c_str(), i->second);
}
}
int main(int argc, char *argv[])
{
profiler.begin("test");
std::vector<std::future<Words>> resources;
resources.reserve(argc - 1);
for (int i = 1; i < argc; ++i)
{
resources.push_back(std::async(loadFromFile, argv[i]));
}
Words words;
for (auto& i : resources)
{
Words results;
try
{
results = i.get();
}
catch (std::exception &err)
{
std::cerr << "ERROR: " << err.what() << '\n';
}
catch (std::string &err)
{
std::cerr << "ERROR: " << err << '\n';
}
for (const auto& j : results)
{
words[j.first] += j.second;
}
}
showResult(words.begin(), words.end());
profiler.end("test");
std::cout << '\n' << profiler.data("test") << " seconds\n";
}
Profiler header file:
#pragma once
#ifndef PROFILER_H
#define PROFILER_H
#include <string>
#include <map>
#include <chrono>
class Profiler
{
public:
struct TimeData
{
TimeData() = default;
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds;
};
void begin(const std::string& name)
{
const auto& it = mData.find(name);
if (it != mData.end())
{
TimeData& time = it->second;
time.start = std::chrono::system_clock::now();
}
else
{
TimeData time;
time.start = std::chrono::system_clock::now();
mData[name] = time;
}
}
void end(const std::string& name)
{
const auto& it = mData.find(name);
if (it != mData.end())
{
TimeData& time = it->second;
time.end = std::chrono::system_clock::now();
time.elapsed_seconds = time.end - time.start;
}
}
double data(const std::string& name)const
{
const auto& it = mData.find(name);
if (it != mData.end())
return it->second.elapsed_seconds.count();
return 0;
}
std::map<std::string, TimeData> mData;
}profiler;
#endif // PROFILER_H
Resource files:
test.txt
File system is huge subject need more work out. file is plain text file This is some junk words. simple program for words counting in text file. 1 2 3 2 2 2 2 @ % & ^ * all so good this test text file
test1.txt
file system second file, test multiple files
Output for non-threaded version:
The most repeated element is: 2 Word Repeated Times --------------------------- 2 5 file 4 text 3 is 3 system 2 test 2 File 1 1 1 need 1 huge 1 subject 1 % 1 more 1 work 1 plain 1 This 1 some 1 program 1 junk 1 words. 1 simple 1 files 1 for 1 words 1 counting 1 in 1 so 1 file. 1 3 1 @ 1 & 1 this 1 ^ 1 file, 1 * 1 all 1 good 1 out. 1 second 1 mulitiple 1 0.0646741 seconds
Output for threaded version:
The first most repeated element is: 2 Word Repeated Times --------------------------- 2 5 file 4 is 3 text 3 system 2 test 2 out. 1 1 1 need 1 huge 1 subject 1 work 1 more 1 % 1 plain 1 This 1 some 1 junk 1 program 1 words. 1 simple 1 files 1 for 1 words 1 counting 1 in 1 file. 1 so 1 3 1 @ 1 & 1 ^ 1 this 1 file, 1 * 1 all 1 good 1 File 1 second 1 mulitiple 1 0.0776089 seconds
<chrono>
to replace the Windows-specific code. \$\endgroup\$