What is the best way to handle vfx: through many threads or one heartbeat event

Currently, I am wondering how I can approach effects in the most performant way. My two options are threads with task.spawn or using one heartbeat event with tables for each “effect” and its properties (like color,position,size).

For threads, it will be very easy to make effects. However, there will be a loop PER effect, and there may be tens or hundreds of effects on scene at once. I thought of using a single heartbeat event to handle all of it, though I am still not sure of its performance. It is also harder to organize it too, since all the properties of an “effect” have to be indexed from a table.

There is once benefit I did notice though: being able to use DeltaTime can benefit lower end devices, so the effects on their screen arent slowed down. I can also stop all the effects from running at once, which may be cool for a time stop ability or something that slows everything down.

Which way should I do: threads (take into account that there may be hundreds of these threads) or one heartbeat event which handles all of the effects. (harder to manage)

If you also need to know how the heartbeat structure would work:
Call a function for an effect
Function creates a table with information about the effect
The table gets added to another table
The heartbeat event loops through each table
If it reached the maximum amount of frames, :destroy it and set the table to nil
if not, have the table "step" and do the movement, rotation, transparency accordingly

For the thread method:

When a function is called, clone a part and set each property
Create a new thread via task.spawn
"step" and do the movement, rotation, transparency accordingly
Destroy it (the part) once the loop in the thread ends