I need help with parallel computing... I don't know how to use it!

Alright, so I’ve been working on this battle simulation lately, and have been scouting out for ways to improve the performance. One thing I came across that could majorly benefit me is roblox’s new parallel computing usage. Only problem is, I DON’T KNOW WHERE TO APPLY IT!

Now, I’m not a math genius or a logistical genius by any means, but I try my best to figure this stuff out. I researched how parallel computing worked, and I only kind of understood it. There are so many tutorials telling you how it works, but they never tell you how to apply it.

If anyone could just look at this short script I have and try and help me pinpoint spots where I could implement this, it would be incredibly appreciated!

PS: I don’t want it to seem like I’m just dumping code and asking for someone to fix it. You don’t have to look at all or any of this code if you don’t want to. I just dropped it here for anyone who wants to see how I could use it. If you don’t want to read all of it I totally understand that, and you could just help me figure out how the hell to do this

-- MAIN SCRIPT (MANIPULATOR)

local RunService = game:GetService("RunService")
local DOS = require(game.ReplicatedStorage.DynamicOctreeSystem)
local Debris = game:GetService("Debris")
local MainModule = require(game.ReplicatedStorage.CharacterHandoffFunctions)

local DosGrid = DOS.New("Name", 4, 400);

local NUM_NPCS = 400

local Teams = {
	["Team1"] = {},
	["Team2"] = {},
}

RunService.Heartbeat:Connect(function(DT)
	
	for Team,NPCs in pairs(Teams) do
		for NPC,Attributes in pairs(NPCs) do
			if Attributes["Target"] then
				
				local MoveVector = MainModule.MoveTo(Teams,DT,NPC,Attributes)
				
				--NPC.Humanoid:Move(MoveVector)
				--NPC.Humanoid.WalkSpeed = Attributes["Velocity"]
				
				if (NPC.PrimaryPart.Position - Attributes["Target"].PrimaryPart.Position).Magnitude < 5 then
					MainModule.Attack(DT,Teams,NPC,Attributes["Target"])
				end
			end
		end
	end
end)

for i = 1,NUM_NPCS do
	
	local NPC1 = MainModule.AddNPC(Teams,"Team1",Vector3.new(math.random(-400,400),2,math.random(-400,400)) + Vector3.new(500,0,-500))
	local NPC2 = MainModule.AddNPC(Teams,"Team2",Vector3.new(math.random(-400,400),2,math.random(-400,400)) + Vector3.new(500,0,500))

	Teams["Team1"][NPC1] = {
		["GoalPos"] = nil,
		["Direction"] = Vector3.new(0,0,0),
		["Target"] = nil,
		["Position"] = Vector3.new(0,0,0),
		["Instance"] = NPC1,
		["MaxVelocity"] = 15,
		["Velocity"] = 15,
		["StrafeDirection"] = "Left",
	}

	Teams["Team2"][NPC2] = {
		["GoalPos"] = nil,
		["Direction"] = Vector3.new(0,0,0),
		["Target"] = nil,
		["Position"] = Vector3.new(0,0,0),
		["Instance"] = NPC1,
		["MaxVelocity"] = 15,
		["Velocity"] = 15,
		["StrafeDirection"] = "Left",
	}
end

local WaitIndex = 0
local MaxIndex = NUM_NPCS/5

while task.wait() do
	for Team,NPCs in pairs(Teams) do
		for NPC,Attributes in pairs(NPCs) do

			local Closest = MainModule.FindClosest(Teams,NPC,Attributes)

			Teams[Team][NPC]["Target"] = Closest

			WaitIndex += 1

			if WaitIndex >= MaxIndex then

				WaitIndex = 0

				task.wait()
			end
		end
	end
end
-- Module script (function handler)

local Module = {}

local DOS = require(game.ReplicatedStorage.DynamicOctreeSystem)
local DosGrid = DOS.New("Name", 4, 400);
local Debris = game:GetService("Debris")

Module.FindClosest = function(Teams,Unit,Attributes)
	
	task.desynchronize()

	local TargetTeam = nil

	if Unit.Team.Value == "Team1" then
		TargetTeam = "Team2"
	else
		TargetTeam = "Team1"
	end

	local PotentialTargets = {}

	local Close = DosGrid.Tree:RadiusSearch(Unit.PrimaryPart.Position,15)

	for _, Object in pairs(Close) do
		if Object.Parent ~= Unit and Object.Name == "HumanoidRootPart" then
			if Object.Parent.Team.Value ~= Unit.Team.Value then
				table.insert(PotentialTargets,Object.Parent)
			end
		end
	end

	local ClosestTarget = nil
	local MinDistance = math.huge
	local MaxSearch = 50
	local Search = 1

	if #PotentialTargets == 0 then

		PotentialTargets = Teams[TargetTeam]

		for Target, Attributes in pairs(PotentialTargets) do

			local RcSkip = math.random(1,2)

			if RcSkip ~= 1 then continue end

			local Distance = (Unit.PrimaryPart.Position - Target.PrimaryPart.Position).Magnitude

			if Distance < MinDistance then

				MinDistance = Distance
				ClosestTarget = Target
			end

			Search += 1

			if Search >= MaxSearch then
				break
			end
		end
	else
		for _, Target in pairs(PotentialTargets) do

			local Distance = (Unit.PrimaryPart.Position - Target.PrimaryPart.Position).Magnitude

			if Distance < MinDistance then

				MinDistance = Distance
				ClosestTarget = Target
			end
		end
	end
	
	task.synchronize()
	
	return ClosestTarget, MinDistance
end

function CheckDeath(Teams,Unit)
	if Unit.HP.Value <= 0 then

		Teams[Unit.Team.Value][Unit] = nil

		Unit:PivotTo(CFrame.new(0,1000,0))

		Debris:AddItem(Unit,1)
	end
end

Module.Attack = function(DT,Teams,Unit,Target)

	local RandomChance = math.random(1,1000 * DT)

	if RandomChance == 1 then

		Target.HP.Value -= math.random(10,30)

		CheckDeath(Teams,Unit)

		Target.Head.Color = Color3.fromRGB(255,255,255)

		delay(.1,function()
			if Target then
				if Target.Team.Value == "Team1" then
					Target.Head.Color = Color3.fromRGB(255,0,0)
				else
					Target.Head.Color = Color3.fromRGB(0,0,255)
				end
			end
		end)
	end
end

function IsBetween(FriendlyA, FriendlyB, Target)

	-- Default to 10 degrees if no angleThreshold is provided
	local angleThreshold = 5

	local v1 = (FriendlyB - FriendlyA).Unit
	local v2 = (Target - FriendlyA).Unit

	local dotProduct = v1:Dot(v2)

	-- Calculate cosine of the angleThreshold
	local cosThreshold = math.cos(math.rad(angleThreshold))

	if dotProduct > cosThreshold and v1.Magnitude <= v2.Magnitude then
		return true
	else
		return false
	end
end

Module.MoveTo = function(Teams,DT,NPC,Attributes)

	local FriendlyInBetween = false
	local TargetPos = Attributes["Target"].PrimaryPart.Position
	local NPCPos = NPC.PrimaryPart.Position
	local Dist = (NPC.PrimaryPart.Position - TargetPos).Magnitude

	-- Avoidance

	local Close = DosGrid.Tree:RadiusSearch(NPCPos,15)

	local goalDirection = (TargetPos - NPCPos).Unit

	for _, closeNPC in ipairs(Close) do
		if closeNPC.Name == "HumanoidRootPart" and closeNPC.Parent ~= NPC then
			
			if closeNPC.Parent.Team.Value ~= NPC.Team.Value then
				continue
			end

			local avoidDistance = (NPCPos - closeNPC.Position).Magnitude

			local avoidDirection = (NPCPos - closeNPC.Position).Unit

			avoidDirection = Vector3.new(avoidDirection.X,0,avoidDirection.Z)

			goalDirection += avoidDirection * (1/avoidDistance) * 2

			if IsBetween(NPCPos, closeNPC.Position, TargetPos) and (NPC.Team.Value == closeNPC.Parent.Team.Value) then
				FriendlyInBetween = true
			end
		end
	end

	goalDirection = goalDirection.Unit

	-- Strafing

	if (NPCPos - TargetPos).Magnitude < 5 then

		local perpDirection = nil

		if Attributes["StrafeDirection"] == "Left" then
			goalDirection = Vector3.new(0, 1, 0):Cross(goalDirection)
		else
			goalDirection = Vector3.new(0, -1, 0):Cross(goalDirection)
		end

		local StrafeChange = math.random(1,10)

		if StrafeChange == 1 then
			if Attributes["StrafeDirection"] == "Left" then
				Attributes["StrafeDirection"] = "Right"
			else
				Attributes["StrafeDirection"] = "Left"
			end
		end
	end
	
	local MoveVector = (Vector3.new(goalDirection.X,0,goalDirection.Z) * DT * 321321)
	
	-- Speed

	if Dist > 40 then
		if Attributes["Velocity"] < Attributes["MaxVelocity"] then
			Teams[NPC.Team.Value][NPC]["Velocity"] += 2.5 * DT
		end
	elseif Dist > 20 then
		if Attributes["Velocity"] < Attributes["MaxVelocity"] then
			Teams[NPC.Team.Value][NPC]["Velocity"] += 1.5 * DT
		end
	end

	if FriendlyInBetween == true and Attributes["Velocity"] > 5 then
		Teams[NPC.Team.Value][NPC]["Velocity"] -= (Attributes["Velocity"]/12)
	end
	
	return MoveVector
	
	--NPC.Humanoid:Move(Vector3.new(goalDirection.X,0,goalDirection.Z) * DT * 321321)

	--NPC.Humanoid.WalkSpeed = Attributes["Velocity"]
end

Module.AddNPC = function(Teams,Team,Pos)

	local NPC = game.ReplicatedStorage.CharacterNPC:Clone()

	NPC.Parent = game.Workspace

	NPC:PivotTo(CFrame.new(Pos))

	Teams[Team][NPC] = {
		["GoalPos"] = nil,
		["Direction"] = Vector3.new(0,0,0),
		["Target"] = nil,
		["Position"] = Vector3.new(0,0,0),
		["Instance"] = NPC,
		["MaxVelocity"] = 15,
		["Velocity"] = 15,
		["StrafeDirection"] = "Left",
	}

	NPC.Team.Value = Team

	DosGrid:Track(NPC.HumanoidRootPart, .25)

	if NPC.Team.Value == "Team1" then
		NPC.Head.Color = Color3.fromRGB(255,0,0)
	else
		NPC.Head.Color = Color3.fromRGB(0,0,255)
	end
	
	return NPC
end

return Module