【发布时间】:2011-01-05 08:21:15
【问题描述】:
考虑以下 shell 脚本:
gzip -dc in.gz | sed -e 's/@/_at_/g' | gzip -c > out.gz
这具有三个并行工作的进程来解压缩流、修改它并重新压缩它。运行time 我可以看到我的用户时间大约是我实际时间的两倍,这表明程序有效地并行工作。
我试图通过将每个任务放在它自己的线程中来在 Java 中创建相同的程序。不幸的是,对于上述示例,多线程 Java 程序仅比single threaded 版本大约30% faster。我试过同时使用Exchanger 和ConcurrentLinkedQueue。 ConcurrentLinkedQueue 链接队列会引起很多争用,尽管所有三个线程通常都保持忙碌状态。 Exchanger 的争用较低,但更复杂,并且似乎无法让最慢的工作人员 100% 地运行。
我试图在不查看字节码编织框架或基于 JNI 的 MPI 的情况下找出解决此问题的纯 Java 解决方案。
大多数并发研究和 API 都与 divide-and-conquer 算法相关,为每个节点提供正交且不依赖于先前计算的工作。并发的另一种方法是管道方法,其中每个工作人员执行一些工作并将数据传递给下一个工作人员。
我并不是想找到最有效的方式来 sed 一个 gzip 文件,而是我正在研究如何有效地分解管道中的任务,以便将运行时间减少到最慢的时间任务。
目前10m行文件的时序如下:
Testing via shell
real 0m31.848s
user 0m58.946s
sys 0m1.694s
Testing SerialTest
real 0m59.997s
user 0m59.263s
sys 0m1.121s
Testing ParallelExchangerTest
real 0m41.573s
user 1m3.436s
sys 0m1.830s
Testing ConcurrentQueueTest
real 0m44.626s
user 1m24.231s
sys 0m10.856s
我悬赏 10% 的 Java 改进,这是在具有 1000 万行测试数据的四核系统上实时测量的。当前资源可在Bitbucket 获得。
【问题讨论】:
-
您在 Java 中所做的代码示例对于提供改进非常有用。很难看出你尝试了什么
-
您是否在多 CPU 机器上进行测试?不确定 JVM 是否可以使用超过 1 个 CPU。
-
我正在运行 Solaris 10 的四核 AMD 机器上进行测试。测试的源代码位于此处:bitbucket.org/brianegge/java-concurrent/src/tip
-
在这项工作的某个时候你不会受到 IO 限制吗?这将限制您可以实现的并行度。
-
好问题!花了将近半天的时间进行测试 :-) 一些争用似乎来自 gc(在 jdk linux 双核上),并且使用更大的读取为此做了一些事情,因为字符串的数量会变得更小。但一切都归结为 java.concurrent 小工具效率不高。我还用管道输入/输出流进行了测试,它们在这里完全没用,因为所有操作都是同步的,一个线程阻塞另一个线程。我想有可能重写那些。
标签: java performance multithreading concurrency