在C++中使用std::copy和async任务的所有目录中的文件列表

1u4esq0p  于 2023-02-01  发布在  其他
关注(0)|答案(2)|浏览(126)

这是一个在C++中使用异步任务完成目录树列表的程序。
我的问题是在每个函数调用中,变量'vect'被创建为一个局部变量,在每个函数调用中,我们有一个目录中的文件列表,但在最后所有目录中的所有文件都被返回到main!这怎么可能?
我的意思是为什么'vect'变量是每个函数调用的局部变量,却保存了由单独的函数调用生成的每个目录的文件名?!这个'vect'的行为就像它是一个全局变量一样。是因为“std::copy”吗?我不明白!

#include <algorithm>
#include <filesystem>
#include <future>
#include <iostream>
#include <vector>

typedef std::vector<std::filesystem::directory_entry> vectDirEntry;

vectDirEntry ListDirectory2(std::filesystem::directory_entry&& dirPath)
{
    std::vector<std::future<std::vector<std::filesystem::directory_entry>>> finalVect;
    vectDirEntry vect;

    for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(dirPath))
    {
        if (entry.is_directory())
        {

            
            std::future<vectDirEntry> fut = std::async(std::launch::async, &ListDirectory2, entry);
            finalVect.push_back(std::move(fut));
        }
        else if (entry.is_regular_file())
        {

            vect.push_back(entry);

        }
    }

    std::for_each(finalVect.begin(), finalVect.end(), [&](std::future<std::vector<std::filesystem::directory_entry>>& fut)

        {
            vectDirEntry lst = fut.get();
            std::copy(lst.begin(), lst.end(), std::back_inserter(vect));
            
        }

    );
    return vect;
}

int main()
{

    const std::filesystem::directory_entry root = std::filesystem::directory_entry("C:/Test");
    std::future<std::vector<std::filesystem::directory_entry>> fut = std::async(std::launch::async, &ListDirectory2, root);
    auto result = fut.get();

    for (std::filesystem::directory_entry& item : result)
    {

        std::cout << item << '\n';

    }
}
gr8qqesn

gr8qqesn1#

每个递归调用都有一个单独的vect,但是当你返回它时,从std::async生成的future会提供每个调用的vect

vectDirEntry lst = fut.get();
        std::copy(lst.begin(), lst.end(), std::back_inserter(vect));

对于每个std::async分派的期货,您使用它们的vect来填充父项的vect(它反过来返回)。
该代码中的lst是由您的一个递归调用返回的vect。该std::copy中的vect是来自 * 当前 * ListDirectory2调用的vect,通过引用隐式接收(因为您以[&]开始lambda定义,这意味着未在λ内声明的任何被引用的变量是对外部范围中的变量的隐式引用)。
这里没什么异常在每次返回之前,您显式地从子vect复制到父vect中,最终在最顶层的ListDirectory2调用中构建最终的vect,该调用包含来自每个递归调用的结果。
顺便说一句,您正在执行一些并非绝对必要的复制,您可以通过将std::copy替换为std::move来避免至少其中的一些复制(除了从r值引用r值的单参数版本之外,还有一个等效于std::copy的三参数版本,它从源代码移动;由于lst参数在每次函数调用结束时过期,因此清空它没有坏处)类似的更改可以是using the insert method of vect and std::make_move_iterator(通过允许向量在每次批量移动之前批量调整大小,可能会稍微快一些),但从std::copystd::move的简单交换是最低限度的解决方案,应该足够快。

ilmyapht

ilmyapht2#

您观察到的情况与async调用无关,而是由于递归。
下面是一个流程图,描述了3个目录级别,每个vect都有一个唯一的名称(它们是程序中唯一的示例)。

ListDirectory2(dir)
vect <- file1.1   // put all files in dir in the local vect
        file1.2
dir1 ---------------> ListDirectory2(dir1) // call ListDirectory2 for each dir
                      vect1 <- file1.1 // put all files in dir1 in the local vect
                               file1.2
                      dir1.1 ---------------> ListDirectory2(dir1.1)
                                              ...
                      vect1 <- std::copy <--- return vect1.1
                      dir1.2 ---------------> ListDirectory2(dir1.2)
                                              ...
                      vect1 <- std::copy <--- return vect1.2
vect <- std::copy <-- return vect1

dir2 ---------------> ListDirectory2(dir2)
                      vect2 <- file2.1 // put all files in dir2 in the local vect
                               file2.2
                      dir2.1 ---------------> ListDirectory2(dir2.1)
                                              ...
                      vect2 <- std::copy <--- return vect2.1
                      dir2.2 ---------------> ListDirectory2(dir2.2)
                                              ...
                      vect2 <- std::copy <--- return vect2.2
vect <- std::copy <-- return vect2
return vect

当调用返回到main时,vect将因此被填充以从起始目录开始的所有文件。

相关问题