Java8 - 在不收集性能的情况下使用流进行映射
Java8 - Mapping with Streams without Collecting for Performance
呈指数级增长的流
我有一个 Stream
以 指数增长 用于创建排列。因此每次调用 addWeeks
都会增加 Stream
.
中的元素数量
Stream<SeasonBuilder> sbStream = sbSet.stream();
for (int i = 1; i <= someCutOff; i++) {
sbStream = sbStream.map(sb -> sb.addWeeks(possibleWeeks))
.flatMap(Collection::stream);
}
// Collect SeasonBuilders into a Set
return sbStream.collect(Collectors.toSet()); // size > 750 000
问题
- 每次调用
addWeeks
return 都是一个 Set<SeasonBuilder>
并将所有内容收集到 Set
中需要一段时间。
addWeeks
不是静态的,需要在流中的每个 SeasonBuilder
上调用,每次通过循环
public Set<SeasonBuilder> addWeeks(
final Set<Set<ImmutablePair<Integer, Integer>>> possibleWeeks) {
return possibleWeeks.stream()
.filter(containsMatchup()) // Finds the weeks to add
.map(this::addWeek) // Create new SeasonBuilders with the new week
.collect(Collectors.toSet());
内存不足错误......当可能的星期有大小 = 15
问题
- 我是否应该使用
map
之后的 flatmap
以外的方法链?
- 如何修改
addWeeks
以便我不必将所有内容都收集到 Set
中?
- 我应该 return 一个
Stream<SeasonBuilder>
吗?我可以flatmap
一个Stream
吗?
更新:
感谢大家的帮助!
我已经把方法的代码放在 gist
感谢@Holger 和@lexicore 建议 return 在 addWeeks
中使用 Stream<SeasonBuilder>
。正如@lexicore
预测的那样,性能略有提高
我尝试使用 parallelStream()
,性能没有显着变化
上下文
我正在创建 Fantasy Football 赛季的所有可能排列,这些排列将在其他地方用于统计分析。在 4 支球队、14 周的赛季中,对于任何给定的一周,都可能存在三种不同的可能性
- (1 对 2) , (3 对 4)
- (1 对 3) , (2 对 4)
- (1 对 4) , (2 对 3)
为了解决这个问题,插入排列,我们就有了所有可能的季节。完毕!但是等等……如果 Team 1 只与 Team 2 比赛怎么办?那么其他球队会很难过。所以对排列有一些限制。
每支球队之间的比赛次数必须大致相同(即 1 队不能在一个赛季中与 3 队比赛 10 次)。在此示例中 - 4 支球队,14 周 - 每支球队最多与另一支球队比赛 5 次。所以在创建排列时必须进行某种过滤,以避免无效的季节。
这变得更有趣的地方是:
- 6 队联赛 -- 可能有 15 周
- 8 队联赛 -- 可能有 105 周
- 10 队联赛 -- 945 周可能
我正在尝试尽可能优化性能,因为有很多排列要创建。考虑到限制条件,一个 4 支球队、14 周的赛季会创造 756 756(=14!/(5!5!4!))个可能的赛季。 6 队或 8 队赛季变得更加疯狂。
你的整个结构从一开始就很可疑。如果您对性能感兴趣,那么显式生成所有排列不太可能是一种好方法。
我也不认为收集设置和再次流式传输是性能问题。
但是,还是要回答你的问题:你为什么不直接从addWeeks
returnStream<SeasonBuilder>
,你为什么先收集它来设置? Return 流目录,不收集:
public Stream<SeasonBuilder> addWeeks(
final Set<Set<ImmutablePair<Integer, Integer>>> possibleWeeks) {
return possibleWeeks.stream()
.filter(containsMatchup()) // Finds the weeks to add
.map(this::addWeek); // Create new SeasonBuilders with the new week
}
那么你就不需要 map
/flatMap
,一个 flatMap
:
sbStream = sbStream.flatMap(sb -> sb.addWeeks(possibleWeeks));
但这对你的表现没有多大帮助。
呈指数级增长的流
我有一个 Stream
以 指数增长 用于创建排列。因此每次调用 addWeeks
都会增加 Stream
.
Stream<SeasonBuilder> sbStream = sbSet.stream();
for (int i = 1; i <= someCutOff; i++) {
sbStream = sbStream.map(sb -> sb.addWeeks(possibleWeeks))
.flatMap(Collection::stream);
}
// Collect SeasonBuilders into a Set
return sbStream.collect(Collectors.toSet()); // size > 750 000
问题
- 每次调用
addWeeks
return 都是一个Set<SeasonBuilder>
并将所有内容收集到Set
中需要一段时间。 addWeeks
不是静态的,需要在流中的每个SeasonBuilder
上调用,每次通过循环public Set<SeasonBuilder> addWeeks( final Set<Set<ImmutablePair<Integer, Integer>>> possibleWeeks) { return possibleWeeks.stream() .filter(containsMatchup()) // Finds the weeks to add .map(this::addWeek) // Create new SeasonBuilders with the new week .collect(Collectors.toSet());
内存不足错误......当可能的星期有大小 = 15
问题
- 我是否应该使用
map
之后的flatmap
以外的方法链? - 如何修改
addWeeks
以便我不必将所有内容都收集到Set
中?- 我应该 return 一个
Stream<SeasonBuilder>
吗?我可以flatmap
一个Stream
吗?
- 我应该 return 一个
更新:
感谢大家的帮助!
我已经把方法的代码放在 gist
感谢@Holger 和@lexicore 建议 return 在 addWeeks
中使用 Stream<SeasonBuilder>
。正如@lexicore
我尝试使用 parallelStream()
,性能没有显着变化
上下文
我正在创建 Fantasy Football 赛季的所有可能排列,这些排列将在其他地方用于统计分析。在 4 支球队、14 周的赛季中,对于任何给定的一周,都可能存在三种不同的可能性
- (1 对 2) , (3 对 4)
- (1 对 3) , (2 对 4)
- (1 对 4) , (2 对 3)
为了解决这个问题,插入排列,我们就有了所有可能的季节。完毕!但是等等……如果 Team 1 只与 Team 2 比赛怎么办?那么其他球队会很难过。所以对排列有一些限制。
每支球队之间的比赛次数必须大致相同(即 1 队不能在一个赛季中与 3 队比赛 10 次)。在此示例中 - 4 支球队,14 周 - 每支球队最多与另一支球队比赛 5 次。所以在创建排列时必须进行某种过滤,以避免无效的季节。
这变得更有趣的地方是:
- 6 队联赛 -- 可能有 15 周
- 8 队联赛 -- 可能有 105 周
- 10 队联赛 -- 945 周可能
我正在尝试尽可能优化性能,因为有很多排列要创建。考虑到限制条件,一个 4 支球队、14 周的赛季会创造 756 756(=14!/(5!5!4!))个可能的赛季。 6 队或 8 队赛季变得更加疯狂。
你的整个结构从一开始就很可疑。如果您对性能感兴趣,那么显式生成所有排列不太可能是一种好方法。
我也不认为收集设置和再次流式传输是性能问题。
但是,还是要回答你的问题:你为什么不直接从addWeeks
returnStream<SeasonBuilder>
,你为什么先收集它来设置? Return 流目录,不收集:
public Stream<SeasonBuilder> addWeeks(
final Set<Set<ImmutablePair<Integer, Integer>>> possibleWeeks) {
return possibleWeeks.stream()
.filter(containsMatchup()) // Finds the weeks to add
.map(this::addWeek); // Create new SeasonBuilders with the new week
}
那么你就不需要 map
/flatMap
,一个 flatMap
:
sbStream = sbStream.flatMap(sb -> sb.addWeeks(possibleWeeks));
但这对你的表现没有多大帮助。