How would i run a function in parallel?

so i’m making a script that raycasts every heartbeat while youre holding e. pretty simple, right? well because i’m doing it all in serial, not parallel, it’s extremely laggy (here’s the micro profiler)

the script looks like this:

local inputconnection = game.ReplicatedStorage.clientbindableevents.sendInput.Event:Connect(function(inputname:string, timesent:number, activity:boolean)
	if os.clock() - timesent > .5 then warn("input sent late") return end
	if inputname == "E" then
		if activity and (Heartbeatconnection == nil or not Heartbeatconnection.Connected) then
			Heartbeatconnection = runservice.Heartbeat:Connect(function()
				local smallestdistance = nil
				local smallestnormal
				local smallestposition
				for i = 1, 16, 1 do
					local angledegree = i * 22.5
					local position, normal, distance = raycast(characterhitbox.Position, Vector3.new(math.cos(math.rad(angledegree)), 0, math.sin(math.rad(angledegree))))
					if distance ~= nil and (smallestdistance == nil or distance < smallestdistance) then
						smallestdistance = distance
						smallestposition = position
						smallestnormal = normal
					end
				print(position, normal)
				end
			end)
		elseif not activity and Heartbeatconnection.Connected then
			Heartbeatconnection:Disconnect()
		end
	end
end)

yeah. so i’m asking how would i run everything in the for loop parallell…ically? i don’t know how to spell that.

Hey! I don’t know if this is exactly what you are looking for, but the function “task.wait(function)” might come useful. You can check roblox’s documentation to learn how it works :slight_smile:

hmm, yeah, that might reduce the lag but it will still slow down the script, which i dont want that. i think that doing something in parallel would be the best solution yet i don’t know how i would do that.
-nevermind, even with task.wait it lags a ton.

1 Like

So you want to split the execution thread? :slight_smile:
Gottu
So in the task library, there is 2 functions you can call to seperate your thread to multiple cores. Now both of these relate to syncing and desyncing. Roblox comes with an automatic :ConnectParallel method for signals. You should replace the heartbeat:Connect() with the heartbeat:ConnectParallel(). ALSO: You must add an actor as the parent of the script. You can then do the parallel connection!

Ask questions!
EDIT (I might be wrong on what you asking, but lowering lag is something right). There is an informative article, and I recommend everything you should read: Parallel Luau | Documentation - Roblox Creator Hub. It also talks about methods and properties you can/can’t access during a parallel phase. Watch out, as some of these methods and properties cannot be called during the parallel threading!

OHH i forgot about the connectparallel, ill try to do this right now

1 Like

Don’t forget the actor and how you can write. Check each property and method u calling so that it doesn’t backfire and load a whole error :skull:

it didn’t work. it still lags a ton.

1 Like

I don’t think running in parallel will help it stop lag:

Why is it so laggy?

  1. When you fire to much RemoteEvent it will cause perfomance issues,
    lets say i hold E key for long time then remote event will constantly fire every 0.5 sec which is not good.

  2. Heartbeatconnection does not disconnects the old ones when
    not pressing E which can cause memory leaks

When trying to make parallel you can use task.spawn(function() but i don’t recommend it

definitely not a memory leak, because in my script i ensure quite well that the connection gets disconnected (i’ve checked).

also, there are no remoteevents because this is a fully local game.

also, i’ve tried task.spawn, it did not help at all.

1 Like
--!strict
--!native
--!optimize 2

local RunService = game:GetService("RunService")

local Heartbeatconnection: RBXScriptConnection? = nil
local characterhitbox: BasePart = nil	

local function raycast(vectore: Vector3,vectorr:Vector3,number:number,numbero:number) 
	--if your function is not just workspace:raycast, then
	-- USE vector.create(0,0,0) INSTEAD OF Vector3, BECAUSE VECTOR.CREATE FASTER

	return vector.create(0,0,0),vector.create(0,0,0),1
end

local inputconnection: RBXScriptConnection = game.ReplicatedStorage.clientbindableevents.sendInput.Event:Connect(function(inputname: string, timesent: number, activity: boolean)
	if os.clock() - timesent > .5 then warn("input sent late") return end

	if inputname == "E" then
		if activity and (not Heartbeatconnection or not Heartbeatconnection.Connected) then
			Heartbeatconnection = RunService.Heartbeat:Connect(function()
				local smallestdistance: number? = nil
				local smallestnormal: vector? = nil
				local smallestposition: vector? = nil

				for i = 1, 16, 1 do
					local angledegree: number = i * 22.5
					local position: vector?, normal: vector?, distance: number? = raycast(characterhitbox.Position, Vector3.new(math.cos(math.rad(angledegree)), 0, math.sin(math.rad(angledegree))))
					if distance and (smallestdistance == nil or distance < smallestdistance) then
						smallestdistance = distance
						smallestposition = position
						smallestnormal = normal
					end
					print(position, normal)
				end
			end)
		elseif not activity and Heartbeatconnection and Heartbeatconnection.Connected then
			Heartbeatconnection:Disconnect()
			Heartbeatconnection = nil
		end
	end
end)

it’s likely that my script is wrong and doesn’t work, but the general gist is: if smg == true then is equivalent to if smg then however, it is faster by one billionth of a second (relatively speaking). Also if not smg then instead of if smg == false then
using the --!strict and --!native directives with full code typing should increase speed by almost 20%
–!optimize 2 is also likely to add speed to the code.

check the pressed button in another script! If it turns out not to be an E, then just don’t bindableEvent:Fire(). It will save you extra milliseconds of optimization.
Of course, parallel luau will definitely help you and will be much better than asynchronous

(Promises and Why You Should Use Them)

Using rays every (every frame) is often overkill. Consider using rays less frequently for example, every 2nd or 3rd frame) and interpolating the results.

If the environment against which you are broadcasting rays changes infrequently, cache the results of some rays. For example, if the player is standing still, you don’t need to re-broadcast the rays in the same direction every frame.
Definitely, prints destroy your optimization. 16 prints every frame is crazy, my PC would explode.

16 rays can be a lot. Think about whether you really need that much. Maybe 12 or 8 is enough.

hmm, i’ll try to do the recieving of the key in the script that sends the bindableevent, then. thanks for your help. by the way, what exactly do --!strict, --!native and --!optimize 2 do? i’ve heard a bit about strict, but not any of the other ones.

I added some information to my last post, you can read it.

--!strict
What it does: Enables strict compilation mode.
It causes warning when using implicit types, uninitialized variables, type casts that may be unsafe, and other potentially problematic places
It helps to identify typos and logical errors at the compilation stage, rather than at runtime, when they are more difficult to debug (probably…)
Why? Fewer errors, more predictable behavior.

--!native
Enables compilation into “native” code.
This tells the client/server to transpile the source code to C++ instead of compiling it to the bytecode by default, this will make your code execute faster at the cost of increased memory, by removing the interpreter overhead to execute per instruction. Basically your script is being translated to another language so that it doesn’t have interpreter input/output.
Native code usually runs significantly faster than interpreted bytecode, as no interpretation overhead is required. as far as I know, this rule works much better with typed code, although I’m not sure why. Probably because Static typing provides the compiler with more information.

--!optimise
These optimizations are basically things that the compiler is confident enough about that it’ll not actually do calculation, for example string.byte("A") is always returning 1 character since that string isn’t gonna ever change, it isn’t a variable or anything so it’s always true. The only exception would be modifying stuff using getfenv() which ofc breaks a lot more than just that. I would expect this feature to break some debugging features if you use those and that’s why it’s not a thing by default on Studio. There might be more optimizations involved that I’m not aware of, that’s just one that seems to be basically confirmed.
(if anything, I just copied this explanation from another person, as I found it quite correct and it will clearly give you more than my explanation in my clumsy English.)

Just know constant printing in the output does have performance hits in studio.

alright, i am going to restructure my code to instead require a module (i don’t want my input reciever to look all messy) in the script that recieves the inputs firsthand, then i’ll make the stuff in the module fire a bit less so for example every third heartbeat, i’ll also make the ray count a bit smaller by reducing it to 8. there is no harm in using a module, right?

Whoa. Even after i got rid of the prints the lag decreased significantly, and when i decreased the ray count from 16 to 8 the lag is (i think…) gone!! Thanks, people.

2 Likes

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