在 grep 克隆中使用 std::future 与 std::thread

问题描述 投票:0回答:1

我最近写了一个

grep
克隆。它对指定目录的所有文件进行字符串查询的递归搜索。程序的核心是如下所示的函数。

/** Do recursive search of query string in files under the given directory.  */
void Search::searchFiles()
{
    std::vector<std::future<void>> futures;
    auto files = fs::recursive_directory_iterator(_directory);
    for (auto& file : files) {
        if (!fs::is_directory(file)) {
            futures.emplace_back(std::async(&Search::searchFile, this, file));
        }
    }
    for (auto & ftr : futures) ftr.wait();
}

我创造了很多未来,但我本可以使用

std::thread
。例如,在下面的代码片段中
searchFiles
使用
std::thread
代替。

void Search::searchFiles()
{
    std::vector<std::thread> threads;
    auto files = fs::recursive_directory_iterator(_directory);
    for (auto& file : files) {
        if (!fs::is_directory(file)) {
            threads.emplace_back(&Search::searchFile, this, file);
        }
    }
    for (auto & th : threads) th.join();
}

其中一种实施方式更好吗? 此外,如何使用迭代器实现

searchFiles
这个想法是创建固定数量的线程,并且如果有更多文件需要获取,每个
searchFile
实例都会增加文件迭代器。下面是我的一个想法的草图。

void Search::searchFile(FileIterator it)
{
    while(true) {

        // get next file from iterator
        std::unique_lock<std::mutex> ulock(_mutex);
        if (it == it.end()) break;
        auto file = *it;
        ++it; 
        ulock.unlock();
        
        // open file and loop through lines.
        std::ifstream filestream(file);
        ...
}

void Search::searchFiles()
{
    std::vector<std::thread> threads;
    auto fileIterator = fs::recursive_directory_iterator(_directory);

    // create only 10 threads
    for (int idx = 0; idx < 10; idx++) {
        if (!fs::is_directory(file)) {
            threads.emplace_back(&Search::searchFile, this, fileIterator);
        }
    }
    for (auto & th : threads) th.join();
}
multithreading c++17 concurrency iterator
1个回答
1
投票

关键绩效指标

其中一种实施方式更好吗?

您没有告诉我们您的关键绩效指标,您的“更好”指标, 如果没有比较标准,它们都同样好。

假设在16核机器上我们以“经过的时间”作为这样的标准。 那么这个提交将是关于性能的, 但它不包括任何性能测量。 OP 可以在其感兴趣的目标主机上记录此类时间;我们不能。

掉队者

有些文件很短,有些文件很长。 该信息可通过 POSIX stat() 调用预先获得。 较长的文件往往意味着基准测试所需的时间较长。 OP代码以任意顺序安排文件, 接近结尾时很有可能出现长文件。 我们称这样的匹配任务为“落后者”, 因为在许多其他核心闲置后,它会让一个核心保持忙碌。

在 N 核机器上,此代码应立即调度 N-1 个任务, 然后识别所有输入文件的大小并对其进行排序。 然后按照大小降序执行剩余的任务。 这保证了在运行结束时我们将分配 持续时间短的任务,因此所有核心往往会在大约同一时间空闲。

© www.soinside.com 2019 - 2024. All rights reserved.