Task Library - Now Available!

Will this have any performance benefits over coroutines and spawn?

3 Likes

Do libraries run on C++? I thought they went through Lua.

1 Like

You shouldn’t be doing this anyways, it’s no wonder it would crash.

I’m not 100% sure, since this is directly using the task manager, I’m assuming the task manager is run on C++.

2 Likes

The fact that there is a crash is a problem regardless of whether or not its good practice to be spawning a bunch of threads.

It turns out the reason is unrelated to the task.spawn calls, a few other people, Hal and I have been discussing and it turns out that task.spawn crashes after a certain number of arguments, and the last few arguments start becoming nil:
task.spawn(print, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48)
Crashes 100% of the time on my machine.
task.spawn(print, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47)
Crashes 0% of the time on my machine, followed by 3 nil values:

The amount of arguments that can be used before a crash seems to differ per machine but weirdly its remained consistent in every test I’ve done, and seems to be consistent for others.

13 Likes

Does task.wait suffer from what is mentioned here, or not?

1 Like

It solves that issue: task.wait(delay) will dutifully unsuspend after the delay regardless of what the performance consequences may be, compared to wait(delay) which “helpfully” throttled execution for you, sometimes delaying resumption by extra frames in an attempt to keep the frame rate smooth.

6 Likes

I can confirm that 44 arguments is currently 100% safe, any more must be avoided for now.

So, as long as you aren’t passing arbitrarily long variable argument lists to the API you won’t run into this issue (unless you actually wrote code that takes more than 44 hand-coded arguments… I won’t judge).

18 Likes

Is it safe to use task.desynchronize and task.synchronize now? Cuz this wasn’t mentioned in this thread.

1 Like

I have the same question. I’d like to make my code as efficient as possible. I know that coroutine isn’t true multitasking, so I’d assume that this new library is effectively just coroutines, but with true multitasking, and can hence be interchangeable. But someone please correct me if I am wrong.

1 Like

Wow. This is amazing. defer and delay will probably be my most used.

This release changes nothing about the status of parallel Lua. This release is only about the functions mentioned in the main post.

5 Likes

This is one of the greatest updates, I’m already starting to use it and I like how simple it is! I’m also looking forward to updates concerning this new library, such as the possibility to cancel!

1 Like

Gosh dang it, not more deprecations. :triumph:
Not saying this is a bad update at all but I already got 6000+ deprecrations and now there’s gonna be more, erugh!

Yes, those methods are meant to be replaced by these.

Don’t worry, for something pervasive like this we’ll give plenty of time for your code to naturally shift over to the new API before bothering you with squiggly lines.

13 Likes

Love all the features added with this update

one small issue I think was missed but when trying to use task.spawn on the running coroutine it crashes

^^ this occurs every time

3 Likes

Why not just write a library to do this? I can’t imagine it’s that difficult to make an object that mirrors this behavior.

Maybe
debounce.fromRBXSignal or debounce.new

1 Like

I think that would be pretty redundant, using debounce by scheduling something to happen later on is already a redundancy, it can be done in a way that is more modern, like comparing the current time in real-time to when it was last executed, that’s far less extraneous in complexity (saves idle polling, and the purpose of the if is clearer.), and makes it quite a bit more accurate.

E.g:

local lastTouch = os.clock()
local debounceTime = 3

local function PartTouched()
    if os.clock() > lastTouch then
        print("The part")

        lastTouch = os.clock() + debounceTime
    end
end
3 Likes

Glad someone mentioned this, I second this completely. Take a look at this hypothetical scenario:

local module = {}
local active = false

local function IncrementStamina()
    if active then
        task.delay(0.5, IncrementStamina)

        -- increment stamina here
    end
end

function Module.Start()
    active = true

    task.delay(0.5, IncrementStamina)
end

function Module.Stop()
    active = false
end

return Module

The problem with this code is that whenever Stop is called, the task.delay internally will still continue scheduling the ‘IncrementStamina’ function for however much time it had remaining, resulting in some idle polling and also makes the function a bit uglier by requiring an if statement to determine if it should still be running. if the Stop function could just be this:

function Module.Stop()
    task.undelay(IncrementStamina)
end

None of those issues would then be present.

However, on the other side of the coin; adding an undelay or similar function with the purpose of cancelling a currently active ‘delayed’ function would require a change to how they store your functions in the queue internally, if that queue weren’t already classed through function memory addresses, it would then have to be for that to work, or anything similar. So I have my doubts that such a function will ever be added, but maybe they’ll find a way. :man_shrugging:

2 Likes