Odwracanie ciągu za pomocą wątków
Niedawno zostałem poproszony w wywiadzie o zaimplementowanie odwrotnej funkcji ciągu za pomocą wątków. Większość z poniższych rozwiązań wymyśliłem. Został wybrany, czy nie, to inna historia :-). Próbowałem uruchomić poniższe rozwiązanie na moim domowym komputerze z podglądem konsumenckim systemu Windows 8. Kompilatorem jest VC11 Beta.
Pytanie brzmi, że kod wielowątkowy jest zawsze tak szybki lub o 1 milisekundę wolniejszy niż kod sekwencyjny. Dane, które podałem, to plik tekstowy o rozmiarze 32,4 MB. Czy istnieje sposób na szybsze tworzenie kodu wielowątkowego? A może dane wejściowe są za małe, żeby coś zmienić?
EDYTOWAĆ
Napisałem tylkovoid Reverse(char* str, int beg, int end, int rbegin, int rend);
ivoid CustomReverse(char* str);
metody w wywiadzie. Cały inny kod jest napisany w domu.
template<typename Function>
void TimeIt(Function&& fun, const char* caption)
{
clock_t start = clock();
fun();
clock_t ticks = clock()-start;
std::cout << std::setw(30) << caption << ": " << (double)ticks/CLOCKS_PER_SEC << "\n";
}
void Reverse(char* str)
{
assert(str != NULL);
for ( int i = 0, j = strlen(str) - 1; i < j; ++i, --j)
{
if ( str[i] != str[j])
{
std::swap(str[i], str[j]);
}
}
}
void Reverse(char* str, int beg, int end, int rbegin, int rend)
{
for ( ; beg <= end && rbegin >= rend; ++beg, --rbegin)
{
if ( str[beg] != str[rbegin])
{
char temp = str[beg];
str[beg] = str[rbegin];
str[rbegin] = temp;
}
}
}
void CustomReverse(char* str)
{
int len = strlen(str);
const int MAX_THREADS = std::thread::hardware_concurrency();
std::vector<std::thread> threads;
threads.reserve(MAX_THREADS);
const int CHUNK = len / MAX_THREADS > (4096) ? (4096) : len / MAX_THREADS;
/*std::cout << "len:" << len << "\n";
std::cout << "MAX_THREADS:" << MAX_THREADS << "\n";
std::cout << "CHUNK:" << CHUNK << "\n";*/
for ( int i = 0, j = len - 1; i < j; )
{
if (i + CHUNK < j && j - CHUNK > i )
{
for ( int k = 0; k < MAX_THREADS && (i + CHUNK < j && j - CHUNK > i ); ++k)
{
threads.push_back( std::thread([=, &str]() { Reverse(str, i,
i + CHUNK, j, j - CHUNK); }));
i += CHUNK + 1;
j -= CHUNK + 1;
}
for ( auto& th : threads)
{
th.join();
}
threads.clear();
}
else
{
char temp = str[i];
str[i] = str[j];
str[j] = str[i];
i++;
j--;
}
}
}
void Write(std::ostream&& os, const std::string& str)
{
os << str << "\n";
}
void CustomReverseDemo(int argc, char** argv)
{
std::ifstream inpfile;
for ( int i = 0; i < argc; ++i)
std::cout << argv[i] << "\n";
inpfile.open(argv[1], std::ios::in);
std::ostringstream oss;
std::string line;
if (! inpfile.is_open())
{
return;
}
while (std::getline(inpfile, line))
{
oss << line;
}
std::string seq(oss.str());
std::string par(oss.str());
std::cout << "Reversing now\n";
TimeIt( [&] { CustomReverse(&par[0]); }, "Using parallel code\n");
TimeIt( [&] { Reverse(&seq[0]) ;}, "Using Sequential Code\n");
TimeIt( [&] { Reverse(&seq[0]) ;}, "Using Sequential Code\n");
TimeIt( [&] { CustomReverse(&par[0]); }, "Using parallel code\n");
Write(std::ofstream("sequential.txt"), seq);
Write(std::ofstream("Parallel.txt"), par);
}
int main(int argc, char* argv[])
{
CustomReverseDemo(argc, argv);
}