GetAttribute/SetAttribute in parallel luau. Best method?

Hi, I really would love to use attributes rather than making instance.new objs (value objects) or even bindables

But I’ve encountered problems in the past using attributes in parallel context

local function MovementEnded(MovementData : MovementData)
--currently in parallel context
	MovementData.MovementHasEnded = true
	--Attempt to fire any connection to the Entity's movement ended event if one exists
	if MovementData.MovementEnded then
		MovementData.MovementEnded:Fire()
	end

end

This is a bindable… Ideally, I’d simply just use a boolean attribute to signal this but I don’t know the proper methodology for the most haste but also performant

Also I believe we can do GetAttribute in parallel correct?

--both tasks start in the asserted context
--assume parallel context outside these task calls
task.defer(function()
		task.synchronize()
		local Character = MovementData.Character
		local Boolean = Character:GetAttribute("MovementEnded") or true
		Character:SetAttribute("MovementEnded", not Boolean)
		
	end)
	--or
	task.spawn(function()
		task.synchronize()
		local Character = MovementData.Character
		local Boolean = Character:GetAttribute("MovementEnded") or true
		Character:SetAttribute("MovementEnded", not Boolean)

	end)

defer and spawn are two different functions
what are you trying to accomplish? if you want the setattribute to be instantaneous, use task.spawn. but i also dont see why you are executing a non-yielding scope with task.spawn.task.defer

The inquiry is in regards to parallel luau execution Im traversing over multiple entities to determine movement stepping. In this scenario, I fire movementended bindable to signal to connected subscribers this entity has stopped moving. But I want to migrate to attributes since its easier to use than physical objects

I want the method closest to the behavior of bindableevent firing but I’m not sure on the exactness…

for note, bindable event fires without care if in parallel or serial execution context, but attributes care. I’m concerned on what method is best for haste and equivalence to bindable

writing SetAttribute is similar to .Value = which is not allowed in Parallel execution. which is why i used task.def/spa for the 1st example (that and I have multiple entities that need assessment, i cant keep spamming task.synch and desynch in the same main thread

local function MovementEnded(MovementData : MovementData)
--currently in parallel context
	MovementData.MovementHasEnded = true
	--Attempt to fire any connection to the Entity's movement ended event if one exists
	--both tasks start in the asserted context
--assume parallel context outside these task calls
task.defer(function()
		task.synchronize()
		local Character = MovementData.Character
		local Boolean = Character:GetAttribute("MovementEnded") or true
		Character:SetAttribute("MovementEnded", not Boolean)
		
	end)
	--or
	task.spawn(function()
		task.synchronize()
		local Character = MovementData.Character
		local Boolean = Character:GetAttribute("MovementEnded") or true
		Character:SetAttribute("MovementEnded", not Boolean)

	end)

end

or


local function MovementEnded(EntityModel, MovementData)
	MovementData.MovementHasEnded = true
	MovementData.EmitMovementEnded = true
end


...

--at the end of the traversed for loop


-- Apply all calculated CFrames by leaving Parallel execution and entering Serial
			task.synchronize()

			-- Process newcframes from the actor and clear out simultaneously
			for i=NumberNew, 1, -1 do
				local EntityModel, SteppedCFrame = NewCFramesModel[i], NewCFramesCF[i]
				EntityModel:PivotTo(SteppedCFrame)
				NewCFramesModel[i] = nil
				NewCFramesCF[i] = nil
				local MovementData = self.Entities[EntityModel]
				if MovementData.EmitMovementEnded then
					local Boolean = EntityModel:GetAttribute("MovementEnded")	
					if Boolean ~= nil then
						EntityModel:SetAttribute("MovementEnded", not Boolean)	
					end
MovementData.EmitMovementEnded = nil
				end
			end

In the end I opted for this, fire movementended without task.def/spa


			-- Apply all calculated CFrames by leaving Parallel execution and entering Serial, Handle deletion of entities.
			task.synchronize()

			-- Process newcframes from the actor and clear out simultaneously
			for i=NumberNew, 1, -1 do
				local EntityModel, SteppedCFrame = NewCFramesModel[i], NewCFramesCF[i]
				EntityModel:PivotTo(SteppedCFrame)
				NewCFramesModel[i] = nil
				NewCFramesCF[i] = nil
				local MovementData = self.Entities[EntityModel]
				if MovementData.EmitMovementEnded then
					
					local Boolean = EntityModel:GetAttribute("MovementEnded")	
					if Boolean ~= nil then
						EntityModel:SetAttribute("MovementEnded", not Boolean)	
					end
					MovementData.EmitMovementEnded = nil
					
				end
				
				-- Process deletion from the actor and clear out simultaneously
				if DeletionQueue[NumberDelete] == EntityModel then
					self.Entities[EntityModel] = nil
					DeletionQueue[NumberDelete] = nil
					NumberDelete-=1
				end
				
			end
1 Like

CHAT GPT SUMMARY:

Summary

Alright, let’s break that post down into plain English, because it’s doing three different things at once: giving technical advice, critiquing mindset, and tossing in some strong opinions.


1. The core disagreement: BindableEvents vs Attributes

The poster is basically saying:

“BindableEvents already do what you want. You’re overthinking this.”

They acknowledge:

  • BindableEvents behave very close to what the original poster wants (event-style signaling).
  • They do cost more memory than attributes because they’re Instances.
  • But since memory constraints weren’t mentioned, there’s no real reason not to use them.

So their stance is:
:backhand_index_pointing_right: If memory isn’t your bottleneck, stop trying to replace BindableEvents with clever attribute hacks.


2. Attributes vs Bindables — functional differences

They point out a key technical difference:

  • Attributes

    • Only trigger AttributeChanged when the value actually changes.
    • Setting the same value twice does nothing.
    • Can’t pass arguments cleanly.
    • Work fine if you only care about state changes (true → false).
  • BindableEvents

    • Fire every time, even if the “value” is conceptually the same.
    • Can pass arguments.
    • Are better for signaling events, not just state.

So the takeaway:

Attributes can imitate events in simple cases, but they are not the same tool, and pretending they are causes weird edge cases.


3. The “painting vs brushstrokes” analogy

This is a mindset critique, not technical advice.

They’re saying:

  • You’re building a game, not a perfectly optimized micro-system.
  • Focusing too hard on tiny implementation details can slow you down.
  • Individual “brushstrokes” (small perf differences) don’t matter much unless they clearly impact the final “painting” (the game).

In other words:

Don’t let premature optimization or architectural purity stall progress.


4. Warning about PivotTo

This part is opinionated but grounded in experience:

  • They warn against using EntityModel:PivotTo(SteppedCFrame)
  • They link a DevForum post showing movement issues (sliding) caused by PivotTo
  • They recommend BulkMoveTo instead, especially for character/entity movement

So:
:backhand_index_pointing_right: PivotTo works, but can cause subtle physics issues. BulkMoveTo is safer for batch movement.


5. Critique of task.spawn / task.defer usage

This is a performance clarification:

They’re saying:

  • Spamming task.spawn / task.defer creates lots of new threads.
  • If the functions don’t yield, this is basically pointless.
  • Running non-yielding code in sequence is often more CPU-efficient.
  • Overusing spawn/defer is effectively like abusing task.synchronize().

Translation:

Parallelism is not free. Don’t create threads unless you actually need concurrency.


6. Final recommended architecture

Their ideal setup:

  • Use BindableEvents
  • Run logic in parallel Luau
  • Only call task.synchronize() when you need to do something engine-bound (like BulkMoveTo)
  • Possibly use one shared MovementEnded BindableEvent instead of one per entity

Why?

  • Cleaner architecture
  • Easier signaling
  • Still performant
  • Less boilerplate

The real summary

This post is basically saying:

  • You’re not wrong, but you’re overengineering
  • BindableEvents are fine and designed for this
  • Attributes are a workaround, not a replacement
  • Don’t obsess over micro-optimizations
  • Use parallelism deliberately
  • Use BulkMoveTo, not PivotTo
  • Pick tools based on structure and clarity first, not raw performance paranoia

If you want, I can also:

  • Rephrase this post in a calmer / less abrasive tone
  • Or help you decide when attributes actually beat bindables in Roblox
  • Or sketch a clean example architecture for the scenario they’re describing

bindable events are not hard to use if you use them right. you’re blaming them for your own shortcomings. i’m not saying this to like get at you but this is overthinking in my opinion.

bindableevents give you what you want, but have a greater memory overhead than attributes because they’re instances. you didn’t specify anything about memory, so you could just use bindableevents.

are you making a painting or a plethora of brushstrokes, as a game dev
i mean: you’re making a game. you can’t get caught up on these tiny things. the painting is composed of the brushstrokes, but one brushstroke means nothing.

oh by the way be careful with EntityModel:PivotTo(SteppedCFrame), pivotTo is not a good function, ion trust that shit. straight up in this code, use BulkMoveTo.

but to actually be helpful-ish, because this is kinda tricky for me to discuss,

first off if you’re using task.spawn or task.defer or whatever, like u did with the first code example, it is no differnt than spamming task.synchronize(). i see that the functions themselves in task.spawn and task.defer are non-yielding and running them in series w/o creating new threads via spawn/defer constantly is more performant on a cpu-usage level than creating the new threads. it doesnt make sense.

with respect to signalling, you CAN use attributes like that. i dont believe attributes fire AttributeChanged when the same value is set twice, making the functionality between bindalbes and attributes different in this sense. if you’re only checking for whether the movementended signal is not the same on the receiving end, e.g. true to false or false to true, as ‘change’, then that’d work functionally. but you cant neatly pass arguments with attributes, thats one of the strengths of bindables imo. you should look at the pros and cons organizationally and structurally before focusing on performance.

i’m sure theres more i can go into but those are my main ideas.

i’d say the final version of your code, with bindableevents in parallel luau, and only calling task,synchronize to call a bulkMoveTo, is ideal for your scenario. performant, in parallel, and works. you could even just have one central MovementEnded bindable and fire them to all the entities that stop moving, rather than one per entity. thats ideal.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.