There are many issues with parenting early which are not simply performance benchmarks. A while ago I ran into an issue where I had parented a part to workspace with the surface type defaulted to studs, upon parenting the engine had automatically created snap joints with the baseplate. Immediately after I set the Parent I would also set the surface types to smooth but since the snaps were already made and they stuck around. Ultimately, my projectiles ended up a little more stationary than intended…
This anecdote may have changed in our iterations of the physics solver, but I think it still serves as a good lesson!
I used option two religiously and started trying and learning option 3 because I find option 1 to be the unwanted method of doing things.
I’m a little frustrated with not being sure what to do about this now, but it could explain some recent lag since a gun framework we use in my clan has the create method. I’m just hoping there’s going to be a optimization at some point for whatever is going on because I’m still in the process of learning new things roblox added on my very long break.
What if I am creating new instances within created instances, even after I set its properties? For example, if I am creating a GUI like this:
local Gui = Instance.new("ScreenGui") local Frame = Instance.new("Frame") -- Give the Frame properties Frame.Parent = Gui local TextLabel = Instance.new("TextLabel") -- Give the TextLabel properties TextLabel.Parent = Frame
Would it be better for me to set the parent of “Gui” to CoreGui after I create all of its children, or would it be better to set its parent first,before I create all of its children and parent its children to it (i.e. ‘Gui = Instance.new(“ScreenGui”, game.CoreGui)’ would replace the first line, as opposed to sticking ‘Gui.Parent = game.CoreGui’ at the end)?
Calling Instance.new with the second argument isn’t the root problem here.
The root problem is that setting Size has a side effect where it runs an extremely expensive collision check to make sure that it doesn’t intersect with nearby parts.
The overhead from resizing becomes worse is in the vicinity of other parts, presumably because the narrowphase of the collision check is really slow. My workstation (i7-4790K, 1070) was struggling to push 5 FPS when I had to resize big parts for the devforum offices.
Is this a good enough excuse to get rid of that behavior?
I always thought this was obvious. Once any instance enters the DataModel, it becomes “tainted”, in that anything might happen to it at any time afterwards, even after it gets removed from the DataModel.
This is why it’s impossible to program gear correctly. This is why using the index operator to get the children of an instance is bad practice. Scripts have no means to acquire ownership of an instance, even temporarily.
So, the solution, when creating an instance from scratch, is to make sure the script has initialized it to complete satisfaction before allowing it to enter the game. And to stop trusting any bit of information it contains from there afterward. Instances should never be used to contain important information; that’s what variables and tables are for. An Instance itself is merely a frontend for whatever effect you want it to have in the game.
Parts are created at the origin, so your assignment of CFrame isn’t actually doing anything. Try changing the CFrame to something like 100,100,100 and you’ll probably get a significant speed loss.
I’ve rewritten Instance.new a bit using that “wait until thread yields” idea.
It’s almost as fast as setting .Parent as last field, much faster than the regular Instance.new(class,parent).
(I said “until thread yields”, but it’s more like “after all pending threads yielded”, can’t do better)
0.00053739547729492 -- Instance.new(a) setFields() setParent()
0.075802326202393 -- Instance.new(a,b) setFields()
0.00056886672973633 -- custom_new(a,b) setFields()
nil -- parent of custom_new(a,b) right after setting the fields
Folder 0.0021722316741943 -- parent + passed time after obj.Changed:wait()
Basically, add the end of the tick, it (only then) sets the parent of all custom_new(a,b) objects.
The “mutex function” only runs once, at the end of the tick that mutex:Fire() got called.
So after wait()or coroutine.yield(), the parent is guaranteed to be set to what you wanted.
Seems like it’s almost as fast as setting the Parent afterwards, but Parent is only set after a semi-tick.
You can also do mutex.Event:wait() if you need to wait until everything (of the current tick) is parented.
TL;DR: “Fixed” Instance.new(a,b), but Parent is only set somewhere before the next tick (it’s still better to just manually replace all Instance.new(a,b) with a variant that sets .Parent afterwards)
One thing I noticed: Instance.new("Part",workspace) takes longer depending on how many parts are already present.
As long as it isn’t a descendant of game, it’s ok.
If your part p would be a descendant of game, it wouldn’t, but that isn’t the case here I think.
So you can create one object, keep adding objects to it and not care about this, then set the top object’s Parent.
The difference between parent/property assignment order for this code exists but is pretty small and unlikely to be measurable unless your hierarchy is much deeper. The main issue is with parenting to game.
So the problem isn’t necessarily with the parent argument, it’s just that changing certain properties of things parented to game can cause performance issues?