В Qt есть возможность параллельного выполнения вашей функции для каждого члена последовательности — QtConcurrent::mapped() и его друзья.
Проблема только в одном — результаты сохраняются в QVector. Поэтому, когда мне понадобилось выполнить свою функцию для 65 миллионов кусочков данных, я не стал мучать оперативку, а написал примерно то же самое, только более ленивое, то есть новые значения будут вычисляться, только если старые уже использовались.
Код: bitbucket.org/cblp/threadpool
ThreadPool наследует QThreadPool. Функция ThreadPool::map() принимает итератор в стиле Java на входе и функцию преобразования, возвращает итератор в стиле Java с результатами.
Ваша функция оборачивается в QRunnable и в количестве M=maxThreadCount штук (как правило, это количество процессоров) закидывается в QThreadPool.
FutureIterator предоставляет методы hasNext() и next(), которые возвращают следующий результат, если он есть, или блокируются, пока следующий результат не будет готов. Если M текущих задач выполнены, а за результатами никто не пришёл, вычислители блокируются.
Прочитать из стандартного ввода строки, от каждой посчитать N-кратный MD5 с солью, результат записать в стандартный вывод. (Это сильно изменённый пример из реальной жизни.)
Всё это пока довольно сыро, например, нельзя запустить в одном бассейне несколько задач так, чтобы они друг другу не мешали. Можете предлагать свои улучшения.
Проблема только в одном — результаты сохраняются в QVector. Поэтому, когда мне понадобилось выполнить свою функцию для 65 миллионов кусочков данных, я не стал мучать оперативку, а написал примерно то же самое, только более ленивое, то есть новые значения будут вычисляться, только если старые уже использовались.
Код: bitbucket.org/cblp/threadpool
Под капотом
ThreadPool наследует QThreadPool. Функция ThreadPool::map() принимает итератор в стиле Java на входе и функцию преобразования, возвращает итератор в стиле Java с результатами.
Ваша функция оборачивается в QRunnable и в количестве M=maxThreadCount штук (как правило, это количество процессоров) закидывается в QThreadPool.
FutureIterator предоставляет методы hasNext() и next(), которые возвращают следующий результат, если он есть, или блокируются, пока следующий результат не будет готов. Если M текущих задач выполнены, а за результатами никто не пришёл, вычислители блокируются.
Пример
Прочитать из стандартного ввода строки, от каждой посчитать N-кратный MD5 с солью, результат записать в стандартный вывод. (Это сильно изменённый пример из реальной жизни.)
const uint N = 10000; const QString Salt = "5417"; QByteArray md5_N_times(QString line) { QByteArray data = line.toUtf8(); for ( uint i = 0; i < N; ++i ) data = QCryptographicHash::hash(Salt.toUtf8() + data, QCryptographicHash::Md5); return data; } int main() { QTextStream input(stdin); QTextStream output(stdout); ThreadPool pool; FutureIterator<QByteArray> results = pool.map( QTextStreamIterator(input), md5_N_times ); while ( results.hasNext() ) output << results.next().toHex() << endl; return 0; }
Всё это пока довольно сыро, например, нельзя запустить в одном бассейне несколько задач так, чтобы они друг другу не мешали. Можете предлагать свои улучшения.
