我做了两个快速排序的实现:顺序和并行.第二个是使用ForkJoinPool编写的,使用了4个线程(我在下面添加了实现) 排序函数与ArrayList配合使用:

override fun sort(array: ArrayList<Int>): ArrayList<Int> { 
   ...
}

我在大小为1e3-1e7的数组上对它们进行了测试,对于所有大小的数组,并行实现的速度大约是顺序实现的2.5倍.但是starting from the size=1e8 parallel algorithm works about 2 times slower,然后是连续的一次.

class ParQuickSort(
    private val seqBlockSize:Int = 1000,
    nThreads: Int = 4
) : QuickSort {

    private val threadPool = ForkJoinPool(nThreads)

    override fun sort(array: IntArray): IntArray {
        threadPool.invoke(
            SortTask(array, 0, array.size - 1, seqBlockSize)
        )
        return array
    }

    fun shutdown() {
        threadPool.shutdownNow()
    }

    private class SortTask(
        val array: IntArray,
        val l: Int,
        val r: Int,
        val seqBlockSize: Int
    ) : RecursiveTask<Unit>() {

        private val rand = Random()

        private val seqSort = SeqQuickSort()

        override fun compute() {
            if (l < r) {
                if (r - l <= seqBlockSize) {
                    seqSort.quickSortInterval(array, l, r)
                    return
                }
                val m = partition(array, l, r)

                invokeAll(
                    SortTask(array, l, m, seqBlockSize),
                    SortTask(array, m + 1, r, seqBlockSize)
                )
            }
        }

        private fun partition(array: IntArray, l: Int, r: Int): Int {
            ...
        }

        private fun swap(array: IntArray, first: Int, second: Int) {
            ...
        }

    }
}

当我更改ArrayList to IntArray时,并行实现显示了1e8数组大小的更好结果(对于较小的数组,其速度大约是顺序的2.5倍).

我知道ArrayList的很多缺点-自动装箱,取消装箱等,IntArray等价于int[],所以它可以处理原语.但是为什么使用ArrayList的并行实现开始只对大量元素(1 e8)给出糟糕的性能?

推荐答案

每个整数占用大约64+64+64位的内存:

  • 对于列表中的每个值,将创建一个Integer实例.这个实例大约128位长:64位由Object头占用(其中,Object头将该对象标识为Integer种类型-对象知道它们是什么,这需要一些内存).
  • ...该实例有一个包含值的字段.你会认为这只是32位.事实并非如此:在64位处理器上,对内存执行的操作不能很好地定位在可以被64位整除的位置,这非常恼人.因此,实际上,64位内存被该32位变量"占用"(从"不再可用于其他东西"的意义上说).
  • 列表本身是一个指针序列,指向那些整数对象(在Java中,"引用").它们是指针).根据JVM的不同方面,每个指针都是64位或32位(压缩OOPS和JVM压缩指针的其他技巧可能适用于此).

相比之下,int[]很简单:每个值占用32位.不多也不少.

也就是说,a factor 6-List<Integer>存储Y个整数所需的内存是int[]的约6倍.(在Kotlin ,据我所知,List<Int>List<Integer>的别名.

因此,此时性能下降的原因很可能是您的主内存已满,正在进行交换.交换已经很昂贵了;当引入并行性时,它往往会变得more昂贵.

Java相关问答推荐

int Array Stream System. out. print方法在打印Java8时在末尾添加% sign

给定Java枚举类,通过值查找枚举

SpringBootreact 式Web应用程序的Spring Cloud Configer服务器中的资源控制器损坏

Spark忽略Iceberg Nessie目录

生成桥方法以解决具有相同擦除的冲突方法

如何在antlr4中跳过所有反斜杠-换行符而保留换行符?

如何从日期中截取时间并将其传递给组件?

为什么我的回收视图会显示重复的列表?

为什么Collectors.toList()不能保证易变性

使用for循环时出现堆栈溢出错误,但如果使用if块执行相同的操作,则不会产生错误

组合连接以从两个表返回数据

如何利用OpenTelemeter将初始值(零)输出到普罗米修斯

Java System.getProperty在哪里检索user.home?

如何在MPAndroidChart中的条形图上正确添加标签

如果c不为null,Arrays.sort(T[]a,Comparator<;?super T>;c)是否会引发ClassCastException?

Spring Mapstruct如何获取Lazy初始化实体字段的信息?

如何在更改分辨率时将鼠标坐标计算为世界坐标

如何使用Jackson读取以方括号开头的JSON?

睡眠在 Spring Boot 中

将在 Docker 中运行的 Spring Boot 连接到在 Docker 中运行的 PostgreSQL,无需 compose 文件?