java - ForkJoinPool 与普通递归

标签 java recursion concurrency forkjoinpool

阅读关于 ForkJoinPool 后,我尝试了一个实验来测试与普通递归相比,ForkJoinPool 的实际速度有多快。

我递归地计算了一个文件夹中的文件数量,令我惊讶的是,普通递归比 ForkJoinPool

执行得更好

这是我的代码。

递归任务

class DirectoryTask extends RecursiveTask<Long> {

    private Directory directory;

    @Override
    protected Long compute() {
        List<RecursiveTask<Long>> forks = new ArrayList<>();
        List<Directory> directories = directory.getDirectories();
        for (Directory directory : directories) {
            DirectoryTask directoryTask = new DirectoryTask(directory);
            forks.add(directoryTask);
            directoryTask.fork();
        }
        Long count = directory.getDoumentCount();
        for (RecursiveTask<Long> task : forks) {
            count += task.join();
        }
        return count;
    }
}

普通递归

private static Long getFileCount(Directory directory) {
        Long recursiveCount = 0L;
        List<Directory> directories = directory.getDirectories();
        if (null != directories) {
            for (Directory d : directories) {
                recursiveCount += getFileCount(d);
            }
        }
        return recursiveCount + directory.getDoumentCount();
    }

目录对象

class Directory {

    private List<Directory> directories;
    private Long doumentCount = 0L;

    static Directory fromFolder(File file) {
        List<Directory> children = new ArrayList<>();
        Long documentCount = 0L;
        if (!file.isDirectory()) {
            throw new IllegalArgumentException("Only directories are allowed");
        }
        String[] files = file.list();
        if (null != files) {
            for (String path : files) {
                File f = new File(file.getPath() + File.separator + path);
                if (f.isHidden()) {
                    continue;
                }
                if (f.isDirectory()) {
                    children.add(Directory.fromFolder(f));
                } else {
                    documentCount++;
                }
            }
        }
        return new Directory(children, documentCount);
    }
}

结果

  • 普通递归:3 毫秒
  • ForkJoinPool:25 毫秒

哪里错了?

我只是想了解是否存在特定阈值,低于该阈值时,普通递归比 ForkJoinPool 更快。

最佳答案

生活中没有免费的东西。如果您必须将一个啤酒箱从您的汽车移动到您的公寓 - 哪个更快:手动将其运送到那里,或者先去棚屋,让手推车用它来移动那个箱子?

创建线程对象是一种“ native ”操作,它会进入底层操作系统以获取那里的资源。这可能是一个相当昂贵的操作。

意思是:仅仅在一个问题上投入“更多线程”并不会自动加快速度。与此相反的。当您的任务主要是 CPU 密集型任务时,并行执行任务可能会带来很小的 yield 。当您进行大量 IO 时,拥有多个线程可以让您总体上“减少”等待;从而提高您的吞吐量。

换句话说:Fork/Join 需要相当多的 Activity 才能完成真正的工作。将它用于只需要几毫秒的计算简直是矫枉过正。因此:您会寻找适用于更大数据集的“fork/join”操作。

要进一步阅读,您可以查看 parallel streams .那些在幕后使用 fork/join 框架;令人惊讶的是,期望任意 parallelStream 也比普通流“更快”是一种误解。

关于java - ForkJoinPool 与普通递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43433874/

相关文章:

java - Android - 尝试创建 'Save file first?"对话框

java - 在 Android 中更改按钮单击的布局

c - 反转数字的递归函数

recursion - 如何在相互递归规则归纳中修复 "Illegal schematic variable(s)"?

C++11线程修改std::list

java - 无法让额外的转义字符在 GSM 7 位字母表中工作。

javascript - 递归 Python 函数转换为 Javascript 不起作用,数组问题

iphone - 如何创建一个始终串行的 GCD 队列,即使在多核 CPU 上也是如此?

java - 所有 ExecutorService 任务完成后程序不会立即终止

java - 将数组列表添加到构造函数中