Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: sync: add batch API to Pool #59348

Closed
rip-create-your-account opened this issue Mar 31, 2023 · 3 comments
Closed

proposal: sync: add batch API to Pool #59348

rip-create-your-account opened this issue Mar 31, 2023 · 3 comments

Comments

@rip-create-your-account

I'm proposing to extend sync.Pool to allow Put() and Get() of multiple objects in a single call. This proposal could be implemented by adding a few new methods:

// PutFromSlice adds all entries from xs to the pool.
//
// It behaves like the following code:
// for _, x := range xs {
//     pool.Put(x)
// }
func (p *Pool[T]) PutFromSlice(xs []*T)
func PoolPutFromSlice[T any](p *Pool, xs []*T) // workaround for no type params on Pool

// FillSlice selects arbitrary items from the Pool, removes them from the Pool,
// and places them into xs.
//
// If there is not enough items to fill the slice, the remaining part of the
// slice is filled with nils. But if p.New is non-nil, the remaining part is
// filled with the results of calling p.New repeatedly.
//
// It behaves like the following code:
// for i := range xs {
//     if x := pool.Get(); x != nil {
//         xs[i] = x.(*T) // panic if conversion fails
//     } else {
//         xs[i] = nil
//     }
// }
func (p *Pool[T]) FillSlice(xs []*T)
func PoolFillSlice[T any](p *Pool, xs []*T) // workaround for no type params on Pool

Without type params the ergonomics of the API would be beyond disgusting. Without it the API would need to take in a slice of []any requiring the users to convert their slices to that type. Or perhaps it would require something equally abhorrent.

The motivation is performance. It's starting to become a pattern in my hot path to have a slice of objects to free or to need. Right now I'm just calling Get/Put in a loop to fill/release such slices. One unfortunately common detail that I have going on is that one goroutine does the Gets and after some processing it's some another goroutine that Puts those objects back to the pool. When under load this ends up meaning that the goroutine doing the Gets mostly ends up taking the slow path of Get(). Get() of a slice of objects surely allows new optimizations in the slow path considering how complex of a data structure Pool is.

@seankhliao
Copy link
Member

I think this works be merged into #47657 given the requirement for a parameterized pool

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Apr 4, 2023
@mpx
Copy link
Contributor

mpx commented Apr 4, 2023

@seankhliao no comment on the merit or approach of this proposal, but I believe it is unrelated to #47657 and should be re-opened.

This proposal (or something like it) would enable batch Get and Put for different numbers of items. Eg, transaction A might Get/Put 3 widgets and transaction B might Get/Put 10 widgets.

@rip-create-your-account
Copy link
Author

That particular issue seems like a good home for this proposal considering that it seems to be a small redesign of the API anyways. I commented my proposal there.

@golang golang locked and limited conversation to collaborators Apr 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants