这是我当前的问题:
我有一个目录结构存储在云存储中的某个位置。在 Root 文件夹下,我有 1000 多个子目录,每个子目录下都有一个子目录。在每个子目录中,都存在一个文件。所以简化图看起来像这样:
Root
________________|________________
| | | |
FolderA FolderB ... FolderY FolderZ
| | | |
Folder1 Folder2 Folder3 Folder4
| | | |
FileA FileB FileC FileD
对于每个节点,它都有属性type
(“目录”或"file")和path
(“/Root/FolderB”)。检索这些节点的唯一方法是调用名为 listDirectory(path)
的方法,该方法会转到云端,获取该 path
内的所有对象。我需要找到所有文件并处理它们。
问题是,按照它的结构方式,如果我想查找 FileA,我需要调用 listDirectory()
三次 (Root -> FolderA ->Folder1),你可以想象它会显着减慢整个过程。
我想以并行方式处理这个问题,但我似乎无法让它工作。我尝试通过使用 GParsPool.withPool
和 eachParallel()
来递归地执行此操作,但我发现使用递归进行并行编程可能是一个危险(且昂贵)的斜坡。我尝试通过创建一个同步列表来线性地执行此操作,该列表保存每个线程访问过的目录的所有路径。但这些似乎都不起作用,也没有为这个问题提供有效的解决方案。
仅供引用,我无法更改 listDirectory()
方法。每次调用都会检索该路径中的所有对象。
TL;DR:我需要找到一种并行的方法来处理云存储文件结构,其中获取文件夹/文件的唯一方法是通过 listDirectory(path)
方法。
最佳答案
如果不能使用守护进程在内存中缓存目录结构。
或者通过最初在内存中创建存储结构的一次性映射并 Hook 到存储的每个添加删除更新操作并相应地更改数据库来缓存目录结构,这不是一种选择。
假设存储结构是树(通常是),因为 listDirectory()
的工作方式我认为你最好使用 Breadth first search搜索存储结构树。这样您就可以使用并行编程一次搜索一个级别
您的代码可能如下所示:
SearchElement.java - 表示目录或文件
public class SearchElement {
private String path;
private String name;
public SearchElement(String path, String name) {
this.path = path;
this.name = name;
}
public String getPath() {
return path;
}
public String getName() {
return name;
}
}
ElementFinder.java - 一个类,用于搜索将 listDirectory 函数替换为实现所需的存储
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
public class ElementFinder {
private final SearchElement ROOT_DIRECTORY_PATH = new SearchElement("/", "");
public Optional<SearchElement> find(String elementName) {
Queue<SearchElement> currentLevelElements = new ConcurrentLinkedQueue();
currentLevelElements.add(ROOT_DIRECTORY_PATH);
AtomicReference<Optional<SearchElement>> wantedElement = new AtomicReference<>(Optional.empty());
while (!currentLevelElements.isEmpty() && wantedElement.get().isEmpty()) {
Queue<SearchElement> nextLevelElements = new ConcurrentLinkedQueue();
currentLevelElements.parallelStream().forEach(currentSearchElement -> {
Collection<SearchElement> subDirectoriesAndFiles = listDirectory(currentSearchElement.getPath());
subDirectoriesAndFiles.stream()
.filter(searchElement -> searchElement.getName().equals(elementName))
.findAny()
.ifPresent(element -> wantedElement.set(Optional.of(element)));
nextLevelElements.addAll(subDirectoriesAndFiles);
});
currentLevelElements = nextLevelElements;
}
return wantedElement.get();
}
private Collection<SearchElement> listDirectory(String path) {
return new ArrayList<>(); // replace me!
}
}
关于java - Groovy/Java : Parallel processing of directory structure where each node is a list of subdirectories/files,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58226567/