消失的可扩展性

我做了一个玩具程序来测试Java的并发性能。 我把它放在这里:https://docs.google.com/open?id=0B4e6u_s5iHT6MTNkZGM5ODQtNjZmYi00NTMwLWJlMjUtYzViOWZlMDM5NGVi

它接受一个整数作为指示有多少线程使用的参数。 该方案只是从一系列计算出的质数。 一个通用的版本是由注释行44〜53得到的,它产生近乎完美的可扩展性。

然而,当我取消注释行44〜53,这在当地做简单的计算和调整可变s到足够大的值,可扩展性可能会消失。

我的问题是我的玩具程序是否使用这可能导致降低并发性能共享的数据。 而如何解释消失的可扩展性(我认为低水平的开销,如垃圾收集,会导致)? 任何解决方案可以解决这样的问题的情况下?

--------------解决方案-------------

有问题的代码是:

int s = 32343;
ArrayList<Integer> al = new ArrayList<Integer>(s);
for (int c = 0; c < s; c++) {
al.add(c);
}
Iterator<Integer> it = al.iterator();
if (it.hasNext()) {
int c = it.next();
c = c++;
}

当然,如果你增加的价值,这将降低性能s ,因为s控制你多少东西放进名单。 但是,有很少做并发或可伸缩性。 如果你写的代码,告诉计算机浪费时间做成千上万个被扔掉的计算,那么当然你的表现会降低。

在更多的技术术语,这部分代码的时间复杂度为O(2n)它需要n操作来生成列表,然后n操作遍历并增加每个值),其中n等于s 。 因此,更大的你让s ,时间越长,将采取执行该代码。

在为什么会似乎使并发的好处而言较小,您曾经考虑过内存影响,因为s变大? 例如,你确定Java堆大到足以容纳任何没有在内存中的一切越来越交换到磁盘? 即使没有得到被换出,通过使长度ArrayList大你给垃圾收集更多的工作要做在运行时(也可能是在增加它的运行频率)。 请注意,根据实施,垃圾收集器,可以在每次运行时暂停所有的线程。

我想知道,如果你分配一个ArrayList每个线程例如,在线程创建的时间,然后再利用,在调用isPrime()而不是每次创建一个新的列表,这是否改善的事情?

编辑:这里有一个固定的后续版本:http://pastebin.com/6vR7Uhez

它给我的机器上输出如下:

------------------start------------------
1 threads' runtimes:
1 3766.0
maximum: 3766.0
main time: 3766.0
------------------end------------------
------------------start------------------
2 threads' runtimes:
1 897.0
2 2483.0
maximum: 2483.0
main time: 2483.0
------------------end------------------
------------------start------------------
4 threads' runtimes:
1 576.0
2 1473.0
3 568.0
4 1569.0
maximum: 1569.0
main time: 1569.0
------------------end------------------
------------------start------------------
8 threads' runtimes:
1 389.0
2 965.0
3 396.0
4 956.0
5 398.0
6 976.0
7 386.0
8 933.0
maximum: 976.0
main time: 978.0
------------------end------------------

...表示几乎线性缩放作为线程的数量是斜坡上升。 我修复的问题是上文和约翰·温顿的(现已删除)回答提出的一个结合点,以及不正确/不必要地使用ConcurrentLinkedQueue结构和一些可疑的时序逻辑。

如果我们使GC日志和配置文件两个版本,我们可以看到,原来的版本大约花费10倍尽可能多的时间运行垃圾收集比修改后的版本:

Original: [ParNew: 17401K->750K(19136K), 0.0040010 secs] 38915K->22264K(172188K), 0.0040227 secs]
Modified: [ParNew: 17024K->0K(19136K), 0.0002879 secs] 28180K->11156K(83008K), 0.0003094 secs]

这意味着,我认为不断的名单分配之间Integer自动装箱,原始的实现只不过是经历了太多的对象,这使在GC,从而降低你的线程的性能,那里是没有好处的点负载太大搅动(甚至是负收益),以创造更多的线程。

所以,这一切对我说的是,如果你想获得良好的向外扩展的Java并发,无论你的任务是大还是小,你要注意你是如何使用内存,要注意潜在的隐藏陷阱和低效的,和优化掉低效位。

分类:java的 时间:2015-03-15 人气:0
本文关键词: Java中,并发
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 1.043 (s). 10 q(s)