- Notifications
You must be signed in to change notification settings - Fork136
Removing unnecessary lazy calls.#605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Removing unnecessary lazy calls.#605
Uh oh!
There was an error while loading.Please reload this page.
Conversation
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
6 similar comments
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
swift-server-bot commentedJul 28, 2022
Can one of the admins verify this patch? |
Lukasa left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for this PR! However, it's not the case that the.lazy has no use because the call is immediately consumed without overhead. Without.lazy,.map will allocate and return anArray. That Array is a performance cost, and we don't want to materialise it.
OliverLetterer commentedJul 28, 2022
dnadoba commentedJul 28, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
You have changed lazy in two places. Lets first talk about about the Lines 606 to 611 in2adca4b
I have slightly modified the test as I wasn't sure how you have created @inline(never)func blackHole(_ value:someAny){}func lazy(){letallobjects=Array(repeating:1, count:100)varcounter=0letduration=ContinuousClock().measure{for_in0..<1_000_000{ counter+=Dictionary(allobjects[0..<40].lazy.map({($0,1)}), uniquingKeysWith:+).values.first!}}blackHole(counter)print("lazy", duration)}func eager(){letallobjects=Array(repeating:1, count:100)varcounter=0letduration=ContinuousClock().measure{for_in0..<1_000_000{ counter+=Dictionary(allobjects[0..<40].map({($0,1)}), uniquingKeysWith:+).values.first!}}blackHole(counter)print("eager", duration)}lazy()eager() which prints in release mode with swift-5.7-DEVELOPMENT-SNAPSHOT-2022-07-17-a: This makes perfect sense as no intermediate array is allocated because However, I think you are right about the second place where you have changed lazy: Lines 612 to 623 in2adca4b
We have manually specified the return type as being an Array, we sadly do allocate an intermediateArray.But flatMap has an overload which actually acceptssome Sequence as the return type from the closure and hence eliminates the intermediate allocation too:https://developer.apple.com/documentation/swift/sequence/flatmap(_:)-jo2yUsing this isn't straight forward though because .lazy.map(_:) will now take an escaping closure and we make a mutating call to self.The solution to this is a bit ugly as we need to use varconnectionToCreate=withoutActuallyEscaping({(eventLoop:EventLoop)->HTTPConnectionPool.Connection.IDinself.createNewOverflowConnection(on: eventLoop)}){ createNewOverflowConnectionOnEventLoopin requiredEventLoopOfPendingRequests.flatMap{ eventLoop, requestCount->LazyMapSequence<LazySequence<StrideTo<Int>>.Elements,(HTTPConnectionPool.Connection.ID,EventLoop)>in // We need a connection for each queued request with a required event loop. // Therefore, we look how many request we have queued for a given `eventLoop` and // how many connections we are already starting on the given `eventLoop`. // If we have not enough, we will create additional connections to have at least // on connection per request.letconnectionsToStart= requestCount- startingRequiredEventLoopConnectionCount[eventLoop.id, default:0]returnstride(from:0, to: connectionsToStart, by:1).lazy.map{ _in(createNewOverflowConnectionOnEventLoop(eventLoop), eventLoop)}}} I haven't tested the performance but I'm quite confident that this will improve performance too as we do not allocate an intermediate array. As this makes the code a bit harder to follow I ended up not using the |
Lukasa commentedJul 29, 2022
In the second case you're right that However, in the case of Dictionary construction there remains insufficient evidence to make the case that this flow optimises the intermediate Array away. That allocation is extraordinarily painful, and it's worth removingeven though |
Lukasa commentedJul 29, 2022
As a sidebar, if we really wanted to make this faster the way to do it is to replace this functional code that feels like it wants to use |




/Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift had unnecessary lazy calls in it. Since the results of the lazy calls are immediately consumed, using lazy here introduces an unnecessary performance overhead!