Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ForkJoinPool与普通递归_Java_Recursion_Concurrency_Forkjoinpool - Fatal编程技术网

Java ForkJoinPool与普通递归

Java ForkJoinPool与普通递归,java,recursion,concurrency,forkjoinpool,Java,Recursion,Concurrency,Forkjoinpool,在阅读了有关的内容后,我尝试了一个实验来测试与普通递归相比,ForkJoinPool的实际速度有多快 我递归地计算了一个文件夹中的文件数,令我惊讶的是,普通递归比ForkJoinPool 这是我的密码 递归任务 class DirectoryTask extends RecursiveTask<Long> { private Directory directory; @Override protected Long compute() {

在阅读了有关的内容后,我尝试了一个实验来测试与普通递归相比,
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;
    }
}
class DirectoryTask扩展了RecursiveTask{
专用目录;
@凌驾
受保护的长计算(){
List forks=new ArrayList();
List directories=directory.getDirectories();
for(目录:目录){
DirectoryTask DirectoryTask=新建DirectoryTask(目录);
add(directoryTask);
directoryTask.fork();
}
Long count=directory.getDoumentCount();
for(递归任务:forks){
count+=task.join();
}
返回计数;
}
}
普通递归

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();
    }
private static Long getFileCount(目录){
长递归计数=0L;
List directories=directory.getDirectories();
if(null!=目录){
用于(目录d:目录){
recursiveCount+=getFileCount(d);
}
}
返回recursiveCount+目录.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);
    }
}
类目录{
私有列表目录;
专用长doumentCount=0L;
静态目录fromFolder(文件){
List children=new ArrayList();
长文档计数=0L;
如果(!file.isDirectory()){
抛出新的IllegalArgumentException(“只允许目录”);
}
String[]files=file.list();
if(null!=文件){
用于(字符串路径:文件){
文件f=新文件(File.getPath()+File.separator+路径);
if(f.ishiden()){
继续;
}
if(f.isDirectory()){
add(Directory.fromFolder(f));
}否则{
documentCount++;
}
}
}
返回新目录(子目录、文档计数);
}
}
结果

  • 普通递归:3ms
  • 游泳池:25毫秒
这里的错误在哪里


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

生活中没有什么是免费的。如果你不得不把一箱啤酒从你的车里搬到你的公寓里,那么什么更快:用手把它运到那里,或者先到棚子里,让手推车用它来搬动那一箱

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

意思是:仅仅在一个问题上抛出“更多线程”并不会自动加快速度。恰恰相反。当您的任务主要是CPU密集型任务时,并行处理可能会带来很小的好处。当你做很多IO时,有多个线程可以让你总体上“少”等待;从而提高您的吞吐量

换句话说:Fork/Join在完成真正的工作之前需要大量的活动。将它用于只需要几毫秒的计算简直是小题大做。因此:您可能希望使用“fork/join”操作来处理更大的数据集


为了进一步阅读,您可以查看。在盖子下使用分叉/连接框架;令人惊讶的是,期望任意
并行流也比普通流“更快”是一种误解。

这有多个方面:

  • 对于同一个问题,串行(例如普通递归)和并行(例如forkjoin)解决方案之间是否存在差异

  • 并行化文件系统访问的范围是什么

  • 衡量绩效的陷阱是什么

  • 对#1的答复。是的,有区别。对于太小的问题,并行性是不好的。对于并行解决方案,您需要考虑以下方面的日常开支:

    • 创建和管理线程
    • 将信息从父线程传递到子线程
    • 将子线程的结果返回到父线程
    • 对共享数据结构的同步访问
    • 等待最慢/最后一个完成的子线程完成
    这些在实践中如何发挥作用取决于多种因素。。。包括问题的规模和并行性的机会

    #2的答案(可能)没有你想象的那么多。典型的文件系统存储在具有物理特性(如磁盘旋转和磁头查找)的磁盘驱动器上。这些通常会成为瓶颈,而且高端存储系统越少,并行性的空间就越小

    #3的答案是有很多陷阱。这些陷阱可能会导致非常误导(即无效)的性能结果。。。。如果你不允许的话。最大的陷阱之一是JVM需要时间“预热”;i、 加载类,进行JIT编译,调整堆大小,等等

    另一个适用于执行文件系统I/O的基准测试的陷阱是,典型的操作系统将执行诸如缓存磁盘块和文件/目录元数据之类的操作。因此,第二次访问文件或目录可能比第一次快


    话虽如此,如果您有一个设计良好的高性能文件系统(例如SSD上的inode)和一个设计良好的应用程序,以及足够的内核,那么就有可能通过并行实现非凡的文件系统扫描速率。(例如,在半小时内检查修改时间戳