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?
All I know is that setting .Size of a part is one of the most expensive property changes I’ve ever seen in my life, and it’s because of these collision checks. Changing a part’s size on Heartbeat is not a good idea right now.
I cannot wait til we are able to remove collisions off of a part.
It’s not quite precise. Changing properties of things parented to game requires additional work (sometimes, a bit; sometimes, a lot). Setting parent first pretty much guarantees that you’re doing a bunch of these redundantly, that can result in performance that ranges from slightly worse than usual to catastrophically worse than usual.
So wouldn’t that mean that just setting the parent directly after creating the object has the same (negative) effect? I think that based on the title, a lot of people are confused and think that calling Instance.new(“Name”, parent) causes performance issues by itself.
Yep, same problem.
If you read his whole post, it’s pretty clear, but I can imagine a lot of people not reading it completely.
Maybe a “TL;DR Only set the Parent property at the very end” would indeed be a good idea.
@zeuxcg (added this mention by editing the post, not sure this even pings the person)