The performance hit isn't too big compared to iterating through the
components. Either with a stream() or a iterator() you're into O(n)
land. Then the O(n + c) where c is some time for the extra method
calls necessary for the stream() becomes negligible. This is
illustrated with the micro benchmark I just ran:

Benchmark                                    Mode  Cnt         Score
     Error  Units
retrieveComponentUsingGet       thrpt   10  24964809.356 ± 195755.618  ops/s
retrieveComponentUsingIterator  thrpt   10   1274221.027 ±  31154.531  ops/s
retrieveComponentUsingStream    thrpt   10   1111762.631 ±   8065.395  ops/s

This is with 100 components added to a page, and retrieving component
with id "50" (each component was issued the index as a string as an
id).

As you can see: using iterator or stream doesn't matter that much.
Using the get() is quote optimal, as we use a Map and index based
lookups when n > 30 or so. Therefore it is an order of magnitute
better: it performs at O(1).

Here's the same benchmark, but now with 100,000 components added to the page.

Benchmark                                    Mode  Cnt         Score
     Error  Units
StreamVsGet.retrieveComponentUsingGet       thrpt   10  25653965.493 ±
268342.736  ops/s
StreamVsGet.retrieveComponentUsingIterator  thrpt   10       795.780 ±
    27.099  ops/s
StreamVsGet.retrieveComponentUsingStream    thrpt   10       756.819 ±
    30.469  ops/s

So in my opinion the performance loss is not too bad, at least when
you don't have a component identifier at your disposal.

I would also add two stream() methods:

- one to stream() the direct children of the markupcontainer
- one to hierarchically stream() all children

The second one is competing with visitChildren(), so might be unnecessary.

Martijn


On Sat, Nov 12, 2016 at 7:36 PM, Andrea Del Bene <[email protected]> wrote:
> I did something similar some time ago. The idea is nice but it was abandoned
> due to performance drawbacks as streams are quite slower than regular
> iteration. Anyway, this is what I did
>
> https://github.com/apache/wicket/commit/73ac8c7e6da3ff9dd0244ad66c63944ba3d64c78
>
>
>
> On 12/11/2016 17:56, Martijn Dashorst wrote:
>>
>> In our code I often see code that (ugh) retrieves a component by id,
>> something like:
>>
>> public class SomePanel extends Panel {
>>      ...
>>         target.add(getPage().get("feedback"));
>>      ...
>> }
>>
>> If we made MarkupContainer streamable, we could, in pseudo code, do
>> something like:
>>
>> getPage().stream().filter(c->c.getId().equals("feedback")).findFirst();
>>
>> Which is not better than getPage().get("feedback")
>>
>> But it is more flexible checking for types, etc.
>>
>> The implementation is not that complicated:
>>
>>
>> /**
>>   * Returns a sequential {@code Stream} with the children of this
>> markup container
>>   *  as its source.
>>   *
>>   * @return a sequential {@code Stream} over the children of this
>> markup container
>>   * @since 8.0
>>   */
>> public Stream<Component> stream()
>> {
>>      return StreamSupport.stream(spliterator(), false);
>> }
>>
>> Good idea?
>>
>> Martijn
>
>



-- 
Become a Wicket expert, learn from the best: http://wicketinaction.com

Reply via email to