mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-04 00:05:25 +08:00
qt 6.5.1 original
This commit is contained in:
32
examples/qtconcurrent/wordcount/CMakeLists.txt
Normal file
32
examples/qtconcurrent/wordcount/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(wordcount LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/wordcount")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(wordcount
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(wordcount PRIVATE
|
||||
Qt6::Concurrent
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS wordcount
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example wordcount
|
||||
\meta tags {threads, console}
|
||||
\title Word Count
|
||||
\ingroup qtconcurrentexamples
|
||||
\brief Demonstrates how to use the map-reduce algorithm.
|
||||
|
||||
The Qt Concurrent \e {Word Count} example demonstrates the use of the
|
||||
map-reduce algorithm when applied to the problem of counting words in a
|
||||
collection of files.
|
||||
|
||||
First, the Application starts a QFileDialog to select a starting
|
||||
path, and then prints the output to the console.
|
||||
|
||||
\include examples-run.qdocinc
|
||||
|
||||
\section1 Comparing the operations
|
||||
|
||||
Compare a single-threaded, sequential approach to counting the words in
|
||||
the text files to a multithreaded approach with mappedReduced():
|
||||
|
||||
\dots
|
||||
\snippet wordcount/main.cpp 1
|
||||
\dots
|
||||
\snippet wordcount/main.cpp 2
|
||||
\dots
|
||||
|
||||
The first argument to the \l {QtConcurrent::}{mappedReduced} function is the
|
||||
container to operate on. The second argument is the mapping function
|
||||
\c {countWords()}. It is called in parallel by multiple threads. The
|
||||
third argument is the reducing function \c {reduce()}. It is called
|
||||
once for each result returned by the mapping function, and generates the
|
||||
final computation result.
|
||||
|
||||
The function returns a QFuture object of type \c WordCount. Call the
|
||||
\l {QFuture::}{result} function immediately on this QFuture to block further
|
||||
execution until the result becomes available.
|
||||
|
||||
\note The mapping function must be thread-safe since it is called from
|
||||
multiple threads.
|
||||
*/
|
152
examples/qtconcurrent/wordcount/main.cpp
Normal file
152
examples/qtconcurrent/wordcount/main.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets/qfiledialog.h>
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <QtCore/qmimedatabase.h>
|
||||
#include <QtCore/qelapsedtimer.h>
|
||||
#include <QtConcurrent/qtconcurrentmap.h>
|
||||
|
||||
typedef QMap<QString, int> WordCount;
|
||||
|
||||
void printHighestResult(const WordCount &, qsizetype);
|
||||
QStringList findFiles(const QString &);
|
||||
|
||||
// Single threaded word counter function.
|
||||
WordCount singleThreadedWordCount(const QStringList &files)
|
||||
{
|
||||
WordCount wordCount;
|
||||
for (const QString &file : files) {
|
||||
QFile f(file);
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream textStream(&f);
|
||||
while (!textStream.atEnd()) {
|
||||
const auto words = textStream.readLine().split(' ', Qt::SkipEmptyParts);
|
||||
for (const QString &word : words)
|
||||
wordCount[word] += 1;
|
||||
}
|
||||
}
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
// countWords counts the words in a single file. This function is
|
||||
// called in parallel by several threads and must be thread
|
||||
// safe.
|
||||
WordCount countWords(const QString &file)
|
||||
{
|
||||
QFile f(file);
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream textStream(&f);
|
||||
WordCount wordCount;
|
||||
|
||||
while (!textStream.atEnd()) {
|
||||
const auto words = textStream.readLine().split(' ', Qt::SkipEmptyParts);
|
||||
for (const QString &word : words)
|
||||
wordCount[word] += 1;
|
||||
}
|
||||
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
// reduce adds the results from map to the final
|
||||
// result. This functor will only be called by one thread
|
||||
// at a time.
|
||||
void reduce(WordCount &result, const WordCount &w)
|
||||
{
|
||||
for (auto i = w.begin(), end = w.end(); i != end; ++i)
|
||||
result[i.key()] += i.value();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
app.setOrganizationName("QtProject");
|
||||
app.setApplicationName(QCoreApplication::translate("main", "Word Count"));
|
||||
|
||||
QFileDialog fileDialog;
|
||||
fileDialog.setOption(QFileDialog::ReadOnly);
|
||||
// Grab the directory path from the dialog
|
||||
auto dirPath = QFileDialog::getExistingDirectory(nullptr,
|
||||
QCoreApplication::translate("main","Select a Folder"),
|
||||
QDir::currentPath());
|
||||
|
||||
QStringList files = findFiles(dirPath);
|
||||
qDebug() << QCoreApplication::translate("main", "Indexing %1 files in %2")
|
||||
.arg(files.size()).arg(dirPath);
|
||||
|
||||
// Start the single threaded operation
|
||||
qint64 singleThreadTime;
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
//! [1]
|
||||
WordCount total = singleThreadedWordCount(files);
|
||||
//! [1]
|
||||
singleThreadTime = timer.elapsed();
|
||||
qDebug() << QCoreApplication::translate("main", "Single threaded scanning took %1 ms")
|
||||
.arg(singleThreadTime);
|
||||
}
|
||||
// Start the multithreaded mappedReduced operation.
|
||||
qint64 mapReduceTime;
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
//! [2]
|
||||
WordCount total = QtConcurrent::mappedReduced(files, countWords, reduce).result();
|
||||
//! [2]
|
||||
mapReduceTime = timer.elapsed();
|
||||
qDebug() << QCoreApplication::translate("main", "MapReduce scanning took %1 ms")
|
||||
.arg(mapReduceTime);
|
||||
qDebug() << QCoreApplication::translate("main", "MapReduce speedup: %1")
|
||||
.arg(((double)singleThreadTime - (double)mapReduceTime) / (double)mapReduceTime + 1);
|
||||
printHighestResult(total, 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function that recursively searches for text files.
|
||||
QStringList findFiles(const QString &startDir)
|
||||
{
|
||||
QStringList names;
|
||||
QDir dir(startDir);
|
||||
static const QMimeDatabase db;
|
||||
|
||||
const auto files = dir.entryList(QDir::Files);
|
||||
for (const QString &file : files) {
|
||||
const auto path = startDir + QDir::separator() + file;
|
||||
const QMimeType mime = db.mimeTypeForFile(QFileInfo(path));
|
||||
const auto mimeTypesForFile = mime.parentMimeTypes();
|
||||
|
||||
for (const auto &i : mimeTypesForFile) {
|
||||
if (i.contains("text", Qt::CaseInsensitive)
|
||||
|| mime.comment().contains("text", Qt::CaseInsensitive)) {
|
||||
names += startDir + QDir::separator() + file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto subdirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
for (const QString &subdir : subdirs) {
|
||||
if (names.length() >= 20000) {
|
||||
qDebug() << QCoreApplication::translate("main", "Too many files! Aborting ...");
|
||||
exit(-1);
|
||||
}
|
||||
names += findFiles(startDir + QDir::separator() + subdir);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// Utility function that prints the results of the map in decreasing order based on the value.
|
||||
void printHighestResult(const WordCount &countedWords, qsizetype nResults)
|
||||
{
|
||||
using pair = QPair<QString, int>;
|
||||
QList<pair> vec;
|
||||
|
||||
std::copy(countedWords.keyValueBegin(), countedWords.keyValueEnd(),
|
||||
std::back_inserter<QList<pair>>(vec));
|
||||
std::sort(vec.begin(), vec.end(),
|
||||
[](const pair &l, const pair &r) { return l.second > r.second; });
|
||||
|
||||
qDebug() << QCoreApplication::translate("main", "Most occurring words are:");
|
||||
for (qsizetype i = 0; i < qMin(vec.size(), nResults); ++i)
|
||||
qDebug() << vec[i].first << " : " << vec[i].second;
|
||||
}
|
7
examples/qtconcurrent/wordcount/wordcount.pro
Normal file
7
examples/qtconcurrent/wordcount/wordcount.pro
Normal file
@ -0,0 +1,7 @@
|
||||
QT += concurrent widgets
|
||||
CONFIG += cmdline
|
||||
|
||||
SOURCES += main.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/wordcount
|
||||
INSTALLS += target
|
Reference in New Issue
Block a user