input.pop_back();
6. Теперь вернем значения из всех функций, которые реализовали ранее. Чтобы ускорить выполнение программы в случае получения очень больших входных данных, запустим их
std::async
принимает политику, функцию и аргументы этой функции. Вызываем функции histogram
, sorted
и vowels
, передавая в качестве политики launch::async
(далее узнаем, что это значит). Все функции получают в качестве аргументов одинаковые входные строки: auto hist (async(launch::async,
histogram, input));
auto sorted_str (async(launch::async,
sorted, input));
auto vowel_count(async(launch::async,
vowels, input));
7. Вызовы async
hist
, sorted_str
и vowel_count
имеют типы, указанные для функций histogram
, sorted
и vowels
, но они обернуты в тип future
функцией std::async
. Объекты этого типа выражают тот факт, что в какой-то момент времени будут содержать значения. Вызов .get()
позволяет получить их все, а до их появления можем заблокировать функцию main
. После получения этих значений выводим их на экран:for (const auto &[c, count] : hist.get()
cout << c << ": " << count << '\n';
}
cout << "Sorted string: "
<< quoted(sorted_str.get()
<< "Total vowels: "
<< vowel_count.get()
}
8. Компиляция и запуск кода выглядят так. Мы использовали короткую строку, которую не стоит распараллеливать, но для примера выполнили ее конкурентно. Вдобавок общая структура программы не изменилась по сравнению с наивной последовательной реализацией:
$ echo "foo bar baz foobazinga" | ./async
: 3
a: 4
b: 3
f: 2
g: 1
i: 1
n: 1
o: 4
r: 1
z: 2
Sorted string: " aaaabbbffginoooorzz"
Total vowels: 9
Как это работает
Если бы мы не использовали std::async, то последовательный нераспараллеленный код выглядел бы довольно просто:
auto hist (histogram(input));
auto sorted_str (sorted( input));
auto vowel_count (vowels( input));
for (const auto &[c, count] : hist) {
cout << c << ": " << count << '\n';
}
cout << "Sorted string: " << quoted(sorted_str) << '\n';
cout << "Total vowels: " << vowel_count << '\n';
Чтобы распараллелить код, мы сделали следующее: обернули три вызова функций в вызовы async(launch::async, ...)
async
запускает новые потоки и позволяет им выполнить функции конкурентно. Таким образом, мы имеем дело только с теми издержками, которые возникают при запуске другого потока, и можем продолжить выполнение следующих строк кода, а вся работа совершится в фоновом режиме:auto hist (async(launch::async
auto sorted_str (async(launch::async
auto vowel_count (async(launch::async
for (const auto &[c, count] : hist.get()
cout << c << ": " << count << '\n';
}
cout << "Sorted string: "
<< quoted(sorted_str.get()
<< "Total vowels: "
<< vowel_count.get()