FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

FpKit now longer uses streams for performance reasons by bbakerman · Pull Request #3932 · graphql-java/graphql-java · GitHub

FpKit now longer uses streams for performance reasons - #3932

Merged
dondonz merged 3 commits into
masterfrom
fpkit-no-longer-uses-streams
May 14, 2025
Merged

FpKit now longer uses streams for performance reasons#3932
dondonz merged 3 commits into
masterfrom
fpkit-no-longer-uses-streams

Conversation

bbakerman commented Apr 27, 2025
edited
Loading

Copy link
Copy Markdown
Member

We no longer uses .stream() since its slower than an imperative style.

The methods were lacking tests so I went all TDD on it and write tests fist with the old streams implementation and then changed it and watched the tests pass

bbakerman changed the title Revert "Revert "FpKit now longer uses streams for performance reasons"" FpKit now longer uses streams for performance reasons Apr 27, 2025
resultMap.put(key, obj);
}
}
return resultMap;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

new common generic function - used in other places

github-actions Bot commented Apr 27, 2025
edited
Loading

Copy link
Copy Markdown
Contributor

Test Results

  312 files  ±0    312 suites  ±0   53s ⏱️ -1s
3 586 tests +5  3 581 ✅ +5  5 💤 ±0  0 ❌ ±0 
3 675 runs  +5  3 670 ✅ +5  5 💤 ±0  0 ❌ ±0 

Results for commit c81cee8. ± Comparison against base commit 262ff2f.

This pull request removes 173 and adds 156 tests. Note that renamed tests count towards both.
	?
                __schema { types { fields { args { type { name fields { name }}}}}}
                __schema { types { fields { type { name fields { name }}}}}
                __schema { types { inputFields { type { inputFields { name }}}}}
                __schema { types { interfaces { fields { type { interfaces { name } } } } } }
                __schema { types { name} }
                __type(name : "t") { name }
                a1: __schema { types { name} }
                a1: __type(name : "t") { name }
                a2 :  __type(name : "t1") { name }
…
graphql.DataFetcherTest ‑ get Boolean property value [fetcher: <graphql.schema.PropertyDataFetcher@7fd69dd propertyName=booleanField function=null>, #0]
graphql.DataFetcherTest ‑ get Boolean property value [fetcher: <graphql.schema.SingletonPropertyDataFetcher@33364212>, #1]
graphql.DataFetcherTest ‑ get Boolean property value with get [fetcher: <graphql.schema.PropertyDataFetcher@23940f86 propertyName=booleanFieldWithGet function=null>, #0]
graphql.DataFetcherTest ‑ get Boolean property value with get [fetcher: <graphql.schema.SingletonPropertyDataFetcher@33364212>, #1]
graphql.DataFetcherTest ‑ get property value [fetcher: <graphql.schema.SingletonPropertyDataFetcher@33364212>, #1]
graphql.DataFetcherTest ‑ get public field value as property [fetcher: <graphql.schema.PropertyDataFetcher@7318daf8 propertyName=publicField function=null>, #0]
graphql.DataFetcherTest ‑ get public field value as property [fetcher: <graphql.schema.SingletonPropertyDataFetcher@33364212>, #1]
graphql.ScalarsBooleanTest ‑ parseValue throws exception for invalid input <java.lang.Object@47e0adb4>
graphql.ScalarsBooleanTest ‑ serialize throws exception for invalid input <java.lang.Object@20094313>
graphql.ScalarsIDTest ‑ parseValue allows any object via String.valueOf <java.lang.Object@52b288a2>
…

♻️ This comment has been updated with latest results.

// The cleanest version of this code would have two maps, one of immutable list builders and one
// of the built immutable lists. BUt we are trying to be performant and memory efficient so
// we treat it as a map of objects and cast like its Java 4x
//

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This comment above explains the whacky code. One less map allocation

Alternative is

public static <T, NewKey> Map<NewKey, ImmutableList<T>> groupingBy(Collection<T> list, Function<T, NewKey> function) {
        Map<NewKey, ImmutableList.Builder<T>> tempMap = new LinkedHashMap<>();
        for (T item : list) {
            NewKey key = function.apply(item);
            tempMap.computeIfAbsent(key, k -> ImmutableList.builder()).add(item);
        }
        Map<NewKey, ImmutableList<T>> resultMap = new LinkedHashMap<>();
        for (Map.Entry<NewKey, ImmutableList.Builder<T>> entry : tempMap.entrySet()) {
            resultMap.put(entry.getKey(), entry.getValue().build());
        }
        return resultMap;
    }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Note two allocations - neater code - worse performance

);
public static <T, NewKey> Map<NewKey, T> toMapByUniqueKey(Collection<T> list, Function<T, NewKey> keyFunction) {
return toMap(list, keyFunction, throwingMerger());
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This was renamed from groupingByUniqueKey to toMapByUniqueKey because its NOT a group by at all. Its a toMap - it was badly named


public static <K, V, U> List<U> mapEntries(Map<K, V> map, BiFunction<K, V, U> function) {
return map.entrySet().stream().map(entry -> function.apply(entry.getKey(), entry.getValue())).collect(Collectors.toList());
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

never used so I removed it - one less stream thing to port

throwingMerger(),
LinkedHashMap::new)
);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

never used - so I removed it - one less stream thing to port

l == ["Parrot"]
}

class Person {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

hey look - TESTS!

We never had very many tests for FpKit

So I I write them first - then changed the implementation

TDD!!!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Noice

Map<NewKey, T> resultMap = new LinkedHashMap<>();
for (T obj : collection) {
NewKey key = keyFunction.apply(obj);
if (resultMap.containsKey(key)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Make it one less statement by looking up the value and save it one call

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Technically not the right semantics in a general sense - sure there could be non

If this map permits null values, then a return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases.

bbakerman added the performance work that is primarily targeted as performance improvements label Apr 27, 2025

public static <T> CompletableFuture<List<T>> flatList(CompletableFuture<List<List<T>>> cf) {
return cf.thenApply(FpKit::flatList);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

never used - no need to port it

return listLists.stream()
.flatMap(List::stream)
.collect(ImmutableList.toImmutableList());
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

never used - no need to port it

return Collections.emptyMap();
}
// Convert builders to ImmutableLists in place to avoid an extra allocation
// yes the code is yuck - but its more performant yuck!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Do you mind if I borrow this line for the release notes?

.add(item);
}
}
if (resutMap.isEmpty()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think you meant to call it a resultMap, anyway not blocking this PR

dondonz commented May 14, 2025

Copy link
Copy Markdown
Member

Leaving a breadcrumb: I have Andi's blessing to approve the PR, he originally had marked this as "changes requested"

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance work that is primarily targeted as performance improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants


Back | FazBrowse Home | New Git URL