Applying a script to items simultaneously

Ah, but that’s what I mean. The for loop runs through individually, rather than simultaneously.

As of now there isn’t a way to run things at the same time without using multiple scripts (which is generally considered bad practice).

Coroutines emulate multithreadedness but only one of them run at a time, meaning it does the same as just using the for loop normally. You can validate this yourself: coroutine.running() only ever prints one thread.

I would do it without coroutines like this:

local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Item = ReplicatedStorage.Item
local ItemFolder = game.Workspace.ItemFolder

local models = CollectionService:GetTagged("models")
local newItems = {} -- use a table to reference the cloned items outside of the for loops scopes
-- use one for loop before the yield
for i,model in pairs(models) do
			local newItem = Item:Clone()
			newItem.Parent = ItemFolder
			newItem.CFrame = model.CFrame
			newItem.Anchored = true
			newItems[i] = newItem
end
--yield 5 seconds
wait(5)
--use a second for loop after the yield to do the destroying
for i,model in pairs(newItems) do
			model:Destroy()
end
--define variables nil for garbage collection
newItems=nil
models=nil
1 Like

This still doesn’t run them at the same time. Doing it in a normal loop will typically be fast enough (unless you have a long yielding function), so creating a seperate table is usually redundant. And there isn’t a reason to wait 5 seconds as the second for loop won’t start until the first one is finished.

Also, you can use setmetatable({}, {__mode = "k"}) instead of just {} to ensure that they get garbage collected.

models will get garbage collected automatically, though i’m not completely sure about this.

I’m confused by what you are saying in your first paragraph. The loops don’t contain yields at all in my solution, so it will execute all at once.

Defining weak keys would be over-engineering for getting rid of a pair of tables, and wouldn’t actually work in this situation- you can’t access the tables for local variables, to set a meta-table.

In many games there are events that run simultaneously. In SkyBlock the plants you have grow simultaneously, for example. I’m sure they didn’t have new scripts for each plant. How could something like that be achieved?

If you don’t have anything that yields, it basically runs all at once. The only thing that “delays” the next iteration would be the amount of time the previous one took to finish (which is a super small amount and can be ignored).

Coroutines are used to emulate multithreadedness, and don’t need to use them here (they don’t help)

i wasn’t aware of this. does doing this not work?

local weakTable = setmetatable({}, {__mode = 'k'})

That would work to clear the contents of weakTable, but not weakTable itself.

Yes, but then weakTable would just be a reference to an empty table, which would then get garbage collected automatically?

But then, using the SkyBlock example again, the plants don’t grow at exactly the same time. Rather, they start growing when you plant them. Maybe you would need a series of for loops to check for each stage of growth?

Weak tables don’t work with instances, instead loop through the table and destroy all models or set the table to nil.

image

Only if the script finishes. If it continues then we’ve wasting memory with the two tables. I think it would be better anyway to chuck the code in a do block instead to automatically get rid of the local variables.

I would just use one loop.

local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")

local growthFactor = 0.1
local stack = setmetatable({}, {__mode = 'k'}) -- still not sure about this

-- event for things being added
CollectionService:GetInstanceAddedSignal("SampleTag"):Connect(function(item)
    table.insert(stack, item) -- push it into the stack
end)

RunService.Heartbeat:Connect(function(deltaTime)
    local _, object = table.remove(stack)
    if not object then return end -- nothing in the stack

    object.growth = object.growth + (growthFactor * deltaTime)
end)
1 Like

So garbage collecting essentially resets the variables, allowing the next item in the for loop to use the variables you’ve set, or?

Garbage collection is how lua deletes items in memory. When there is no more references to an item, such as an instance, table, or string, it is deleted. It is something to consider to prevent memory leaks.

1 Like

Sorry for my lack of knowledge. What is so bad about memory leaks, what does a memory leak effect?

In short your computer and roblox’s servers can store a certain amount of information which includes everything in your game, memory leaks are where you hold onto information you don’t need- like a model that you have destroyed. It’s unnecessary to keep and just prevents that memory being used for other purposes.

1 Like

Here you are using weak keys correctly, I only specified how they wouldn’t work as I thought you were talking about getting rid of the reference to the table, not the values it references itself, which was why I nilled newItems and models in my first reply.

1 Like

You can use coroutines.

coroutine.wrap(function()
  Do something here...
end)()

The code above will wrap a coroutine which basically created a coroutine and returns a function to resume it.

The wrapped coroutine then gets called by the () after the ‘coroutine.wrap` call. The code inside the function will be ran in a different thread.

1 Like