编写并发程序 Inversion
做完了 scala parallel 课程作业后,觉得 scala 写并发程序的便捷性是 java 永远都追不上的。scala 的Future 和 Promise,java 里 Future 和 CompleteFuture 实现了类似的功能,但是使用的便捷性还差的很远,java.util.Future 本身 API 较少,不支持链式操作。CompleteFuture 丰富了 Future 的 API,但是也不好用。
这里用 Scala parallel 学到的东西计算 Inversion. Inversion 叫做逆序对,它的 nlogn 算法的思想是在 merge sort 的 Merge 阶段计算逆序对的个数。先列出单线程解法。
public static long sort(List<Integer> numbers, int left, int right) {
if(left >= right) return 0L;
if(left + 1 == right) return 0L;
int mid = (right - left) / 2 + left;
long leftInversion = sort(numbers, left, mid);
long rightInversion = sort(numbers, mid, right);
long mergeInversion = merge(numbers, left, mid, right);
return (leftInversion + rightInversion + mergeInversion);
}
public static long merge(List<Integer> numbers, int left, int mid, int right) {
List<Integer> buf = new ArrayList<>();
int leftCursor = left, rightCursor = mid;
long inversion = 0;
while(leftCursor < mid && rightCursor < right) {
if(numbers.get(leftCursor) <= numbers.get(rightCursor)) buf.add(numbers.get(leftCursor ++));
else {
buf.add(numbers.get(rightCursor ++));
inversion += (mid - leftCursor);
}
while(leftCursor < mid) buf.add(numbers.get(leftCursor ++));
while(rightCursor < right) buf.add(numbers.get(rightCursor ++));
for(int i = 0; i < (right - left); i ++) numbers.set(i+left, buf.get(i));
return inversion;
}
}
做 benchmark 一定要注意同一段程序要 run 多遍,以最后一遍的运行时间为准,因为预热阶段包括对内存的填充,线程的创建等等。
在我的 4 核 i7 mac 上跑了三轮,10万数字的 inversion, 时间分别是 100ms, 70ms, 40ms.
然后是并行解法。并行解法使用了 ForkJoinPool,别的 threadPool 也是一样的,但是性能上是否有区别就不知道了。
为了避免每次执行任务都要创建 ForkJoinTask, 先写一个 wrapper.
public abstract class TaskScheduler {
public abstract <T> ForkJoinTask<T> schedule(Function<Void, T> func);
}
public class DefaultTaskScheduler extends TaskScheduler {
public <T> ForkJoinTask<T> schedule(Function<Void, T> func) {
ForkJoinTask<T> task = new ForkJoinTask<T>() {
protected T compute() { return func.apply(null); }
};
ForkJoinCom.pool.execute(task);
return task;
}
}
有了这个 Wrapper 以后,就可以通过 schedule 函数直接把运算逻辑变成 ForkJoinTask。
merge 是顺序执行的,写不出它的并行实现,但是 sort 函数是分而治之算法,每次把 List 划分为不相交的两段,可以并行的对这两段排序。
public static long parSort(List<Integer> nums, int left, int right, int threshold) {
if(right - left <= threshold) return Inversion.sort(nums, left, right);
int mid = (right - left) /2 + left;
ForkJoinTask<Long> leftTask = ForkJoinCom.scheduler.schedule(Void -> parSort(nums, left, mid, threshold));
ForkJoinTask<Long> rightTask = ForkJoinCom.scheduler.schedule(Void -> parSort(nums, mid, right, threshold));
long leftInversions = leftTask.join();
long rightInversions = rightTask.join();
long mergeInversions = Inversion.merge(numbers, left, mid, right);
return leftInversions + rightInversions + mergeInversions;
}
到这里,并行解法就算写完了,但是性能提升的并不明显。尝试调整 threshold, 调整 ForkJoinPool 的线程数目,效果依然不明显。回忆 scala 作业题里老师给出的实现,突然想到,当 leftTask, rightTask 正在执行的时候,当前线程只是傻等着,什么都没干,这是对 CPU 资源的浪费。照着这个思路稍微修改了下 parSort 方法:
编写并发程序 Inversion的更多相关文章
- 【Java并发基础】利用面向对象的思想写好并发程序
前言 下面简单总结学习Java并发的笔记,关于如何利用面向对象思想写好并发程序的建议.面向对象的思想和并发编程属于两个领域,但是在Java中这两个领域却可以融合到一起.在Java语言中,面向对象编程的 ...
- CSharpGL(11)用C#直接编写GLSL程序
CSharpGL(11)用C#直接编写GLSL程序 +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharp ...
- 在Linux上编写C#程序
自从C#开源之后,在Linux编写C#程序就成了可能.Mono-project就是开源版本的C#维护项目.在Linux平台上使用的C#开发工具为monodevelop.安装方式如下: 首先需要安装一些 ...
- 35.按要求编写Java程序: (1)编写一个接口:InterfaceA,只含有一个方法int method(int n); (2)编写一个类:ClassA来实现接口InterfaceA,实现int method(int n)接口方 法时,要求计算1到n的和; (3)编写另一个类:ClassB来实现接口InterfaceA,实现int method(int n)接口 方法时,要求计算n的阶乘(n
35.按要求编写Java程序: (1)编写一个接口:InterfaceA,只含有一个方法int method(int n): (2)编写一个类:ClassA来实现接口InterfaceA,实现in ...
- 如何让VS2013编写的程序
总体分c++程序和c#程序 1.c++程序 这个用C++编写的程序可以经过设置后在XP下运行,主要的“平台工具集”里修改就可以. 额外说明:(1)程序必须为Dotnet 4.0及以下版本.(XP只支持 ...
- 编写一个程序,求s=1+(1+2)+(1+2+3)+…+(1+2+3+…+n)的值
编写一个程序,求s=1+(1+2)+(1+2+3)+…+(1+2+3+…+n)的值 1 #import <Foundation/Foundation.h> 2 3 int main( ...
- 在Salesforce中通过编写C#程序调用dataloadercliq的bat文件取触发调用data loader来批量处理数据
通过这篇文章 http://www.cnblogs.com/mingmingruyuedlut/p/3413903.html 我们已经知道了Data Loader可以对Salesforce的Objec ...
- 转 : 用Delphi编写安装程序
http://www.okbase.net/doc/details/931 还没有亲自验证过,仅收藏 当你完成一个应用软件的开发后,那么你还需要为该软件做一个规范化的安装程序,这是程序设计的最后一步 ...
- 初学编写JAVA程序
一.编写JAVA程序 编写JAVA程序,输出一行文本信息:“Hello world”,选择编辑器eclipse,打开之后编写程序 public class Hello{ public static v ...
随机推荐
- Dynamic CRM 2013学习笔记(十六)用JS控制Tab可见,可用
一个Form里经常会有好几个Tab,有时要根据一些条件设置哪些Tab可用,可见.下面就介绍下如何用JS对Tab进行控制. 1. 控制可见 function setTabVisableByName( ...
- 跟我一起学WCF(12)——WCF中Rest服务入门
一.引言 要将Rest与.NET Framework 3.0配合使用,还需要构建基础架构的一些部件.在.NET Framework 3.5中,WCF在System.ServiceModel.Web组件 ...
- [OpenCV] 4、图像叠加 addWeighted
>_<" 这次主要是图像叠加的基本操作: >_<" cv::addWeighted(imageROI, 1.0, logo, 0.6, 0, imageRO ...
- PAAS平台的web应用性能测试与分析
引言 为什么我会写这一篇博客,因为最近很多京东云擎jae的用户反应一个问题就是他们部署在jae上面的应用访问很慢,有极少数应用甚至经常出现504超时现象,当然大家首先想到的是jae性能太差,这也是人之 ...
- JavaScript 中的 this ,看着一篇就够了
tip 在 js 中,this 这个上下文总是变化莫测,很多时候出现 bug 总是一头雾水,其实,只要分清楚不同的情况下如何执行就 ok 了. 全局执行 首先,我们在全局环境中看看它的 this 是什 ...
- atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制
atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制 1. token机制and session保持状态机制 1 ...
- paip.http 404错误 的解决
paip.http 404错误 的解决 错误原因 1.查看web服务器log...看是否错误... 2.使用了spring 或者struts 等等mvc框架,但是设置错误.. 3.web服务器使用了配 ...
- VS2013编译经常卡在正在从以下位置加载xxx.dll的符号
换了系统后,重新下载了一个vs2013 with update2安装,编译的时候总是卡在 正在从以下位置加载xxx.dll的符号 如图: 解决方法: 进入VS---工具---选项----调试----符 ...
- iOS开发-迭代器模式
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示.开发过程中,我们可能需要针对不同的需求,可能需要以不同的方式来遍历整个整合对象,但是我们不希望 ...
- iOS开发---集成百度地图完善版
一.成为百度的开发者.创建应用 http://developer.baidu.com/map/index.php?title=首页 (鼠标移向 然后选择你的项目需要的功能 你可以在里面了解到你想要使用 ...