How to reuse the same coroutine

Would creating multiple coroutines every minute affect performance or should I just create a function?

2 Likes

I don’t think there’s any way to reuse a coroutine once it’s in a dead state.

You can use coroutine.yield() though to pause it, but I don’t think this is what you want.

1 Like

As @C_Sharper said. I’m pretty sure you can’t revive and reuse a dead coroutine, so using coroutine.yeild() would likely be a good choice, and using coroutine.resume() to unpause it.

Create a while true loop that yields.

local coro = coroutine.create(function()
    while true do
        --arguments
        local a,b,c = coroutine.yield()
        --code here
        print(a, b, c)
    end
end)
coroutine.resume(coro)

-- call the coroutine now as much as you want
coroutine.resume(coro, 1,2,3)
coroutine.resume(coro, 4,5,6)
coroutine.resume(coro, 7,8,9)
1 Like

Multiple coroutines every minute? Coroutines just run code seperately, theres nothing inherently slow about them. You dont need to reuse coroutines, just make a new one when you need them.

this is not a good idea
every minute, you probably won’t see a difference
but if it’s for example every frame, it can pretty decent difference

garbage collecting and doing memory allocations for a coroutine every frame is pretty roundabout when you can just re-use a coroutine

if i remember correctly, someone said it’s one of the reasons why GoodSignal is faster than SimpleSignal

you’re right, but this poster was wondering if multiple coroutines per minute, the reason good signal is good is because if you use signals a lot then it can result in using them many times per frame.

as nooneisback shows, architecting your code to reuse your coroutine requires a lot of boilerplate (although if you have a way to make it cleaner i’d love to see it), saying making new coroutines “is not a good idea” isn’t painting the whole picture.

plus, even when you do reuse a coroutine, all the memory allocated by the coroutine’s run cycle would have to be freed anyway to make room for the next coroutine cycle.

Try this:

local function myFunction() -- function coroutine will run
     print("foo, bar!")

     task.wait(3)

     print("bar, foo!")
end

local c1 = coroutine.create(myFunction)
local c2 = coroutine.create(myFunction)

coroutine.resume(c1)
coroutine.resume(c2)

You reuse the same function, for 2 coroutines. But of course, you cannot reuse a coroutine once it’s in it’s dead state. It may as well garbage collected.

adding onto this point, luau caches functions

when running these two tests
image

image

they both output the same amount (16.00390625 MB)

the reason that defining the function out of scope is useful is because it doesn’t lock the in-scope memory

for i = 1, 1000000 do
	local a = "hi"
	task.spawn(function()
		task.wait(10)
		--the garbage collector can't pick out "a" until this function finishes
		--which means "a" is locked in memory for 10 seconds
	end)
end
function test()
	task.wait(10)
	--this function isn't locking any variables because its not in the scope of them
end

for i = 1, 1000000 do
	local a = "hi"
	task.spawn(test)
end

anyways
lemme just post a code for a custom spawn function that can reuse coroutines.

local spawn: (functionOrThread: (...any) -> () | thread, ...any) -> (thread) do
    local freeThread: thread?
    local function passFunc(func: (...any) -> (), ...: any): ()
        local thread = freeThread :: thread
        freeThread = nil
        func(...)
        freeThread = thread
    end

    local function newThread(): ()
        freeThread = coroutine.running()
        while true do passFunc(coroutine.yield()) end
    end

    spawn = function(functionOrThread: (...any) -> () | thread, ...: any): thread
        if type(functionOrThread) ~= "function" then return task.spawn(functionOrThread) end
        if not freeThread then task.spawn(newThread) end
        return task.spawn(freeThread :: thread, func, ...)
    end
end