I hope this will scale with the amount of players or in some other way. A server with around 10 players might not even need multi-threading, but it is a must on servers with over 50 players. Also, some genres like RTSs would benefit much more than more casual ones.
Iāve made some upgrades to my parallel terrain generator since the previous revision.
Itās hard to really show it off in one clip though, best to check it out for yourself!
ParallelTerrain.rbxl (55.4 KB)
Hopefully I can test this in a live game soon.
good stuff. ive been wondering what this actor stuff that ive been seeing around was. finally the uncomfortable feeling of crunching a lot of numbers in a synchronous thread is gone, at least partially. the explanation was a little confusing, though; why is writing to instances restricted? id think that as soon as an instance is written to that write would be visible to other scripts like normal. if this isnt the case, why? if it is the case, whats the problem?
Iām curious how youāre going to approach this given how Luau VM stacks currently work with ModuleScripts.
It would be nice if the synchronised phase could access the root global state of a module though, whether thats possible or not, is another question
The reason scripts under an Actor have a different view of module scripts even during the synchronous phase is because a native lua object canāt move between VMs. The module root is a lua table, so it would have to be copied by value into the other VM, which is expensive and likely not what you want.
The shared storage will likely be an object that isnāt a native lua object and is thread safe.
I saw you typing btw, also with the allowance of multiple threads have an impact on improving FPS and increasing render distance?
The biggest problem with writing to instances at the moment is that changing a property triggers the Changed event, possibly in another VM, that is already running a different thread. We plan to make more properties writable over time.
Itās not the main goal, but it could help with client FPS under some rare circumstances.
I think this update is really good and promises a lot of new possibilities. Well done!
Just finished my ECS lib too, Iāll be using this in future projects. Thanks for all the good work!
I love it!
Iāve been waiting for it since the developer preview and im so excited to finally start using it in my projects.
.
.
.
Btw i think you forgot to lock the ātaskā table
Is this behavior intentional?
When you require a module and try to connect something in parallel in a function you call from another script it will cause the error āScripts that connect in parallel must be rooted under an Actor.ā, but it works just fine when you do the same from within the module script.
Modulescript:
script.Parent = Instance.new("Actor")
local function thisRunsFine()
Instance.new("BindableEvent").Event:ConnectParallel(function() end)
end
thisRunsFine() --this works
return thisRunsFine
Script:
local moduleScript = script.ModuleScript
thisCausesAnError = require(moduleScript) --this works
thisCausesAnError() --this causes an error
That behavior isnāt intentional per sea. The main purpose of the error is a learning aid, that stops a user whoās new to the system from just changing Connect to ConnectParallel without setting up actors and thinking they have made things parallel. In a module script you might write a function thatās called by both scripts that are and are not under Actors, so for now we donāt throw this informative error. This may change in the future.
Overall, couldnāt understand this a lot, if someone can sum it up thatād be appreciated.
I have to say, I only understood half of what you were saying. Iām just going to wait for a youtube video to come out. Also, are there any resources for a more in-depth explanation of everything? I understand the basic premise of scripts running on different hardware threads, but thatās the limit of my understanding. Will there be an article tutorial about this?
This sounds incredible and all, but Iām just thinking about how on Earth Iām gonna switch my games to this new featureā¦
Switching them is not necessary nor is something you should be doing unless needed.
Wish there was a more clear and concise description and examples of how the functions exactly work and their intended usecase. The only example really given was with :ConnectParallel
, which doesnāt really say much anyways.
After checking over clonetroopers example and eventually making sense of the post, I pretty much figured out some ways it works and its not terribly complicated, just convoluted.
--[[
This with :ConnectParallel()
ConnectParallel initiates task.desynchronize without needing to add it manually.
According to the main post, its a much faster way of running a task in parallel,
but may not always be convenient personally.
]]
local radius = 5
local function Paralleltest()
local circumference = 2 * math.pi * radius
local area = (circumference^2)/4*math.pi
--[[
I'm not entirely clear on how roblox handles the dividing of tasks between threads,
given that they actively decided against the ability to manually create threads as
you would be able to do in other languages such as C. So i presume it automatically
distributes tasks across threads as it sees fit. So the more complex of a task you're
running parallel, the better it scales? Otherwise its just a slightly better coroutine.
]]
task.synchronize() --This should sync up the work done and allow for it to be properly read/used.
--Do note that editing properties is not considered thread safe for good reason, you can only handle math and other non-interactive tasks via parallel
print(circumference, area)
end
event:ConnectParallel(Paralleltest)
--This is assuming its connected to an event of some sorts, a bindable or heartbeat are both valid examples
--This is with task.desynchronize()
local function paralleltask()
task.desynchronize() --At least i think this is how its done? The documentation is extremely vague and its worked in testing so correct me if i am wrong
--[[
A roughly similar idea as with ConnectParallel, although its manually
invoked as opposed to automatically running via an event. This is
likely a useful way of handling heavy math orientated tasks, or the sorting
of large tables. I imagine this could also do wonders for pathfinding API's,
as many of them struggle with being bottlenecked by a single core.
]]
local circumference = 2 * math.pi * radius
local area = (circumference^2)/4*math.pi
task.synchronize()
print(circumference, area)
end
paralleltask()
--[[
In practice, the implementation seems rather simple, albeit unnecessary for those who don't want to rewrite code to handle it.
Its really only practical if you need it, otherwise its superfluous. But I'd suggest trying to implement it anyways if you
have a lot of stuff handled on the server and its causing some performance bottlenecks. I'm sure theres more to it though,
so it might be worth waiting until its officially implemented rather than
trying to learn it now while theres room for it to radically change.
]]
Any chance that this will support GuiObjects as itās childs?
As of how it is right now you can only add ScreenGuis as its child, not Frames, Labels, Buttons or TextBoxes.
I have a bunch of code that I have running on the client that I would like to have multithreaded in the near future. Since LocalScripts canāt run under workspace unless theyāre in the local playerās character model, how would we go about having multithreaded local code that retrieves information about a model and its descendants? I could be understanding Actors wrong, but donāt the scripts need to be inside of the actor theyāre reading/writing to?