Pooler | Let's go for a swim!

Documentation | Wally | GitHub

Pooler is a simple instance pooler. It recycles objects to prevent constant Instance.new() and instance:Destroy() calls.

It’s more performant to recycle objects than destroy and recreate them. Whilst the differences are small, when the time it takes adds up, your game will be a lot slower by removing and creating instances when compared to using an instance pooler. Things like bullet hell games will almost certainly require instance pooling to run fast enough since creating and destroying thousands of objects will be extremely expensive on either the server of client.

I’m aware there are other more mature and more battle-tested instance poolers out there, and a lot of people will write their own for each project. I wanted my own pooler that did what I needed it to do, and I decided to open-source it and distribute it.

Pooler is designed to take any instance type, not just parts. The majority of poolers I’ve seen can only accept parts and the ones I’ve seen that don’t do not have much customizability. I needed both, so I wrote Pooler to handle both cases. It can pool anything, but it still has the ability to use the optimized techniques for BaseParts and Models when required.

Pooler is a dead simple library to use. Your existing code might look like this:

local Debris = game:GetService("Debris")

local template = Instance.new("Part")

template.Anchored = false

template.Material = Enum.Material.Neon
template.BrickColor = BrickColor.Green()

while true do
    local instance = template:Clone()
    instance.Parent = workspace

    Debris:AddItem(instance, 3)

    task.wait()
end

This is obviously a very bizarre use case, but let’s roll with it. Converting this to Pooler is quite an easy task.

  1. Add Pooler to your script:
local Pooler = require(script.Parent.Pooler) -- or wherever your copy might be...
  1. Create your instance pool:
local pool = Pooler.new(template)
  1. Swap out your :Clone() and :AddItem() calls for the Pooler equivalents:
while true do
    local instance = pool:Get()
    instance.Parent = workspace

    task.delay(3, function()
        pool:Return(instance)
    end)

    task.wait()
end

Pooler is available on GitHub or on Wally.

28 Likes

I know a lot more people would use this if it was a roblox model, I don’t know about anyone else but I tend to only take code that is published on roblox, besides that this looks very cool!

2 Likes

To be fair though, I wouldn’t be surprised if a FPS game benefited a ton from this, with the constant creation and destruction of bullets. It may not seem like a big difference but as @lewisakura said it all adds up in the end.

At first i didn’t understand the purpose of this module so I looked into debris service and now I’m pretty sure that I understand it. What its basically doing is destroying the part for you but it won’t delay a thread, won’t create a new one, and it shouldn’t error if the part is already gone. (Correct me if I’m wrong please. Just trying to understand). In other words, this module seems useful, and I will most definitely consider trying to use this in my game I’m working on.

I thought this was some sort of a water simulation library, well that turned out to be very wrong :expressionless:

7 Likes

Object caches are really good to use if you’re using a lot of instances over and over again. I really recommend this to anyone who suffers from Instance.new performance problems. (good for creating tons of bullets every second, etc)

This might be the one time my cheesy pun taglines probably isn’t worth it, sorry for the disappointment :sweat_smile:

1 Like

Sorta!

This module is designed to prevent destroying and recreating instances, instead encouraging the idea of reusing ones you already have. The entire idea of pooling is to create a bunch of these objects at once and recycle them instead of creating them as you need them, then destroying them later. Since creating and destroying is a relatively expensive operation, this saves time by creating all the instances you’ll ever need to begin with, then you can just reuse them over and over in your game. No destruction until you are certain you’ll never need them again!

I just don’t know how to say this. It’s just so good, and improves performance a lot! Btw, question; How is the pool:Return(instance) used?

Depends. If you’re using the default settings, you don’t have to return anything yourself since the pool will do that for you when the object it gets is already in use.

If you’re running in exhaustion mode or you want to manually return it anyway, you just pass the instance you got when running pool:Get() to pool:Return(), like so:

local instance = pool:Get()
-- do some stuff with it...
pool:Return(instance)
1 Like

1.0.1 has been released to fix a typo that wasn’t spotted in 1.0.0 which causes an error when passing an options object without a getMethod. Not sure how this got through my test suites but things happen I suppose.

Very useful and lightweight, I appreciate the time you’ve spent on making this available to us.