Java 拆分器并行排序顺序
我正在实现一个分页拆分器(Java),它应该允许并行访问 我有以下测试用例(测试在Groovy和Spock中进行):Java 拆分器并行排序顺序,java,java-8,spliterator,Java,Java 8,Spliterator,我正在实现一个分页拆分器(Java),它应该允许并行访问 我有以下测试用例(测试在Groovy和Spock中进行): def“并行,两页”() { 当:“排序范围从0到6” def fetcher=新的IntegerRangePageFetcher(6) 和:“页面大小为5的拆分器” def拆分器=新页面拆分器(取数器,5) 和:“具有给定范围的流被收集到列表” def result=StreamSupport .流(拆分器,真) .collect(收集器.toList()) 然后:“遵守排序顺
def“并行,两页”()
{
当:“排序范围从0到6”
def fetcher=新的IntegerRangePageFetcher(6)
和:“页面大小为5的拆分器”
def拆分器=新页面拆分器(取数器,5)
和:“具有给定范围的流被收集到列表”
def result=StreamSupport
.流(拆分器,真)
.collect(收集器.toList())
然后:“遵守排序顺序”
预期结果,包含(0、1、2、3、4、5)
}
此测试用例失败,出现以下错误:
Condition not satisfied:
expect result, contains(0, 1, 2, 3, 4, 5)
| |
false [5, 0, 1, 2, 3, 4]
Expected: iterable containing [<0>, <1>, <2>, <3>, <4>, <5>]
but: item 0: was <5>
当我不使用parallel时,代码可以工作。所以我不明白的顺序
:
- 如果设置了,流框架是否应该保证顺序,并在使用并行生成的块时对结果进行排序?如果是,为什么不在我的案例中进行排序
- 或者我的
实现中是否有错误,必须按照给定的顺序进行拆分?(当前我在打开的页面中间拆分,0-mid保留在当前拆分器中,mid-end保留在新创建的拆分器中)trySplit
- 或者我应该在
之前调用collect()
,因为框架根本不能保证任何顺序sort()
@覆盖
公共拆分器trySplit()
{
//第一个问题
if(pageIterator==null){
pageIterator=pageFetcher.fetchNextPage(paginationInfo);
}
//代理拆分决策
var newPaginationInfo=paginationInfo.split();
if(newPaginationInfo==null){
log.info(“*Spliterator返回null”);
返回null;
}
//现在我们分手了
var newSpliterator=new PagedSpliterator(pageFetcher,newPaginationInfo);
返回newSpliterator;
}
公共分页信息拆分()
{
//当开放范围或什么都没有留下时,我们不会分割
如果((endElementIndex=-1)| |!hasNextPage()){
返回null;
}
//计算分裂位置
var firsthallpages=(getEndPageIndex()-getNextPageIndex())/2;
var midElementIndex=(getNextPageIndex()+firstHalfPages)*页面大小;
//创建额外的PaginationInfo并根据拆分位置设置范围
var newPaginationInfo=新的PaginationInfo(此);
newPaginationInfo.firstElementOnNextPageIndex=midElementIndex;
newPaginationInfo.nextElementIndex=midElementIndex;
endElementIndex=中间元素索引;
返回newPaginationInfo;
}
第一个错误:
新创建的拆分器设置为第二个半范围,而不是第一个半范围。我在文档中读到了前缀,但我觉得它很笨拙。我按页面大小进行拆分,以获得多个并行请求。在开始时(第一个spliterator实例),我必须获取第一个页面以获取页面和元素计数器。因此,为了解决顺序问题,我必须将从第一个拆分器获取的数据分发给第二个拆分器,以遵守顺序,这让我感觉非常奇怪,而且不直观
第二个错误:
//第一次查询
if(pageIterator==null){
pageIterator=pageFetcher.fetchNextPage(paginationInfo);
}
所有后续创建的拆分器将从框架接收一个estimateSize()
和一个trySplit()
调用。在此调用过程中,我当前获取一个页面,但这将阻止并行性,获取必须稍后在tryAdvance()
调用中进行
我将实现这些更改,然后返回给您。是的,您的trySplit中有一个bug。Spliterator.trySplit的文档指定,如果您具有有序特征,则返回的Spliterator必须包含元素前缀。切换返回的拆分器和拆分器的剩余内容。来自
trySplit
的文档:
如果订购了此拆分器,则返回的拆分器必须包含元素的严格前缀
您的实施:
。。。0-mid停留在当前的拆分器上,mid-end进入新创建的拆分器
你可以从这里连接正确的点 我们应该猜一下您的拆分器是如何实现的吗?我还想知道您是否过度拆分了。你什么时候停止分裂?当存在单个元素时?