Con el aplicación de modeladode programación Parallel Luau , puedes ejecutar código en múltiples hilos simultáneamente, lo que puede mejorar el rendimiento de tu experiencia.A medida que expandes tu experiencia con más contenido, puedes adoptar este modelo para ayudar a mantener el rendimiento y la seguridad de tus scripts de Luau.
aplicación de modeladode programación paralela
Por defecto, los scripts se ejecutan secuencialmente.Si tu experiencia tiene lógica o contenido complejo, como personajes no jugadores (NPC), validación de raycasting y generación procedural, entonces la ejecución secuencial podría causar retrasos para tus usuarios.Con el aplicación de modeladode programación paralela, puedes dividir tareas en múltiples scripts y ejecutarlos en paralelo.Esto hace que el código de tu experiencia se ejecute más rápido, lo que mejora la experiencia del usuario.
El modelo de programación paralela también agrega beneficios de seguridad a tu código.Al dividir el código en múltiples subprocesos, cuando editas código en un subproceso, no afecta a otro código que se ejecuta en paralelo.Esto reduce el riesgo de tener un error en tu código que corrompa toda la experiencia y minimiza el retraso para los usuarios en los servidores en vivo cuando envías una actualización.
Adoptar el modelo de programación paralela no significa poner todo en múltiples hilos.Por ejemplo, la validación de lanzamiento de rayos del lado del servidor establece cada usuario individual un evento remoto en paralelo, pero aún requiere que el código inicial se ejecute en serie para cambiar las propiedades globales, que es un patrón común para la ejecución paralela.
La mayoría de las veces necesitas combinar fases seriales y paralelas para lograr tu Salidadeseada, ya que actualmente hay algunas operaciones que no se admiten en paralelo que pueden impedir que se ejecuten los scripts, como modificar instancias en fases paralelas.Para obtener más información sobre el nivel de uso de API en paralelo, vea seguridad del hilo.
Separar el código en múltiples hilos
Para ejecutar los scripts de tu experiencia en múltiples hilos simultáneamente, debes dividirlos en pedazos lógicos bajo diferentes actores en el modelo de datos .Los actores se representan por Actor instancias que heredan de DataModel.Funcionan como unidades de aislamiento de ejecución que distribuyen la carga entre múltiples núcleos que se ejecutan simultáneamente.
Colocar instancias de actor
Puedes poner actores en contenedores apropiados o usarlos para reemplazar los tipos de instancia de alto nivel de tus entidades 3D como NPCs y lanzadores de rayos, luego agrega los scripts correspondientes.

Para la mayoría de las situaciones, no deberías poner a un actor como hijo de otro actor en el aplicación de modeladode datos.Sin embargo, si decide colocar un script anidado dentro de múltiples actores para su caso de uso específico, el script es propiedad de su actor ancestro más cercano.

Dessincronizar hilos
Aunque poner scripts bajo actores les otorga la capacidad de ejecución paralela, por defecto el código aún se ejecuta en el hilo único en serie, lo que no mejora el rendimiento de tiempo de ejecución.Necesitas llamar a la función task.desynchronize(), una función rentable que suspende la ejecución de la coroutine actual para ejecutar código en paralelo y lo reanuda en la próxima oportunidad de ejecución paralela.Para cambiar un script de ejecución serial a ejecución secuencial, llame a task.synchronize() .
Alternativamente, puedes usar el método RBXScriptSignal:ConnectParallel() cuando quieras programar una llamada de señal para ejecutar inmediatamente tu código en paralelo al activarse.No necesitas llamar task.desynchronize() dentro de la devolución de llamadade señal de devolución.
Dessincronizar un hilo
local RunService = game:GetService("RunService")
RunService.Heartbeat:ConnectParallel(function()
... -- Algo de código paralelo que calcula una actualización de estado
task.synchronize()
... -- Algún código serial que cambia el estado de las instancias
end)
Los scripts que forman parte del mismo actor siempre se ejecutan secuencialmente con respecto a los demás, por lo que necesitas múltiples actores.Por ejemplo, si pones todos los scripts de comportamiento habilitados en paralelo para tu NPC en un actor, aún se ejecutan en serie en un solo subproceso, pero si tienes múltiples actores para diferentes lógicas de NPC, cada uno se ejecuta en paralelo en su propio subproceso.Para obtener más información, vea Mejores prácticas.


Seguridad del hilo
Durante la ejecución paralela, puedes acceder a la mayoría de las instancias de la jerarquía DataModel como de costumbre, pero algunas propiedades y funciones de la API no son seguras para leer o escribir.Si los usa en su código paralelo, el motor de Roblox puede detectar y prevenir automáticamente que ocurran estos accesos.
Los miembros de la API tienen un nivel de seguridad de hilo que indica si y cómo puedes usarlos en tu código paralelo, como muestra la siguiente tabla:
Nivel de seguridad | Para propiedades | Para funciones |
---|---|---|
No seguro | No se puede leer o escribir en paralelo. | No se puede llamar en paralelo. |
Leer paralelo | Se puede leer pero no escribir en paralelo. | N/A |
Caja fuerte local | Se puede utilizar dentro del mismo actor; se puede leer pero no escribir por otros Actors en paralelo. | Se puede llamar dentro del mismo actor; no se puede llamar por otros Actors en paralelo. |
Seguro | Se puede leer y escribir. | Se puede llamar. |
Puedes encontrar etiquetas de seguridad de hilo para miembros de la API en la referencia de API.Al usarlos, también debe considerar cómo las llamadas de API o los cambios de propiedad pueden interactuar entre hilos paralelos.Por lo general, es seguro que múltiples actores lean los mismos datos que otros actores, pero no modifiquen el estado de otros actores.
Comunicación entre hilos
En el contexto de multihilo, aún puedes permitir que los scripts de diferentes actores se comuniquen entre sí para intercambiar datos, coordinar tareas y sincronizar actividades.El motor soporta los siguientes mecanismos para la comunicación entre subprocesos:
- Mensajería de actor API para enviar mensajes a un actor usando scripts.
- Estructura de datos de tabla compartida para compartir eficientemente una gran cantidad de datos entre múltiples actores en un estado compartido.
- Comunicación directa del modelo de datos para una comunicación simple con restricciones.
Puedes apoyar múltiples mecanismos para satisfacer tus necesidades de comunicación entre hilos.Por ejemplo, puedes enviar una tabla compartida a través de la API de mensajería de actor.
Mensajería de actor
La API de mensajería de actores permite que un script, ya sea en un contexto serial o paralelo, envíe datos a un actor en el mismo aplicación de modeladodatos.La comunicación a través de esta API es asincrónica, en la que el remitente no bloquea hasta que el receptor reciba el mensaje.
Al enviar mensajes usando esta API, necesitas definir un tema para categorizar el mensaje.Cada mensaje solo se puede enviar a un solo actor, pero ese actor puede tener internamente múltiples llamadas de devolución vinculadas a un mensaje.Solo los scripts que son descendientes de un actor pueden recibir mensajes.
La API tiene los siguientes métodos:
- Actor:SendMessage() para enviar un mensaje a un actor.
- Actor:BindToMessage() para vincular una llamada de devolución de llamada Luau a un mensaje con el tema especificado en un contexto serial.
- Actor:BindToMessageParallel() para vincular una llamada de devolución de llamada Luau a un mensaje con el tema especificado en un contexto paralelo.
El siguiente ejemplo muestra cómo usar Actor:SendMessage() para definir un tema y enviar un mensaje en el finalizardel remitente:
Remitente de mensaje de ejemplo
local Workspace = game:GetService("Workspace")-- Envía dos mensajes al actor trabajador con un tema de "Saludo"local workerActor = Workspace.WorkerActorworkerActor:SendMessage("Greeting", "Hello World!")workerActor:SendMessage("Greeting", "Welcome")print("Sent messages")
El siguiente ejemplo muestra cómo usar Actor:BindToMessageParallel() para vincular un llamado de devolución para un determinado tema en un contexto paralelo en el finalizardel receptor:
Receptor de mensajes de ejemplo
-- Obtener al actor al que este guión está asociado
local actor = script:GetActor()
-- Vincular una llamada de devolución para el tema de mensaje "Saludo"
actor:BindToMessageParallel("Greeting", function(greetingString)
print(actor.Name, "-", greetingString)
end)
print("Bound to messages")
Tabla compartida
SharedTable es una estructura de datos tabular accesible desde scripts que se ejecutan bajo múltiples actores.Es útil para situaciones que implican una gran cantidad de datos y requieren un estado compartido común entre múltiples hilos.Por ejemplo, cuando varios actores trabajan en un estado mundial común que no se almacena en el aplicación de modeladode datos.
Enviar una tabla compartida a otro actor no hace una copia de los datos.En cambio, las tablas compartidas permiten actualizaciones seguras y atómicas por parte de múltiples scripts simultáneamente.Cada actualización de una tabla compartida por un actor es inmediatamente visible para todos los actores.Las tablas compartidas también se pueden clonar en un proceso eficiente de recursos que utiliza la compartición estructural en lugar de copiar los datos subyacentes.
Comunicación directa del modelo de datos
También puedes facilitar la comunicación entre múltiples hilos directamente usando el aplicación de modeladode datos, en el que diferentes actores pueden escribir y luego leer propiedades o atributos.Sin embargo, para mantener la seguridad del hilo, los scripts que se ejecutan en paralelo generalmente no pueden escribir en el aplicación de modeladode datos.Así que usar directamente el modelo de datos para la comunicación viene con restricciones y puede obligar a los scripts a sincronizarse con frecuencia, lo que puede afectar el rendimiento de tus scripts.
Ejemplos
Validación de lanzamiento de rayos del lado del servidor
Para una experiencia de combate y batalla, debes habilitar raycasting para las armas de tus usuarios.Con el cliente que simula las armas para lograr una buena latencia, el servidor debe confirmar el golpe, que implica hacer raycasts y una cantidad de heurísticas que calculan la velocidad esperada del personaje y miran el comportamiento pasado.
En lugar de usar un solo script centralizado que se conecta a un evento remoto que los clientes usan para comunicar la información de los golpes, puedes ejecutar cada proceso de validación de golpes en el lado del servidor en paralelo con cada personaje de usuario que tenga un evento remoto separado.
El script del lado del servidor que se ejecuta bajo el evento remoto de ese personaje Actor se conecta a este evento remoto utilizando una conexión paralela para ejecutar la lógica relevante para confirmar el golpe.Si la lógica encuentra una confirmación de un golpe, se deduce el daño, lo que implica cambiar las propiedades, por lo que se ejecuta en serie inicialmente.
local Workspace = game:GetService("Workspace")
local tool = script.Parent.Parent
local remoteEvent = Instance.new("RemoteEvent") -- Crear un nuevo evento remoto y asignarlo como padre a la herramienta
remoteEvent.Name = "RemoteMouseEvent" -- Renombra para que el script local pueda buscarlo
remoteEvent.Parent = tool
local remoteEventConnection -- Crear una referencia para la conexión de evento remoto
-- Función que escucha un evento remoto
local function onRemoteMouseEvent(player: Player, clickLocation: CFrame)
-- SERIAL: Ejecutar el código de configuración en serie
local character = player.Character
-- Ignorar el carácter del usuario al intersección rayo-superficie, emisión de rayos
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { character }
-- PARALELA: Realizar el raycast en paralelo
task.desynchronize()
local origin = tool.Handle.CFrame.Position
local epsilon = 0.01 -- Se usa para extender el rayo ligeramente ya que la ubicación de clic podría estar ligeramente desplazada desde el objeto
local lookDirection = (1 + epsilon) * (clickLocation.Position - origin)
local raycastResult = Workspace:Raycast(origin, lookDirection, params)
if raycastResult then
local hitPart = raycastResult.Instance
if hitPart and hitPart.Name == "block" then
local explosion = Instance.new("Explosion")
-- SERIAL: El código siguiente modifica el estado fuera del actor
task.synchronize()
explosion.DestroyJointRadiusPercent = 0 -- Hacer que la explosión no sea mortal
explosion.Position = clickLocation.Position
-- Múltiples actores podrían obtener la misma parte en un raycast y decidir destruirla
-- Esto es perfectamente seguro, pero resultaría en dos explosiones a la vez en lugar de una
-- Los siguientes controles dobles aseguran que la ejecución llegó a esta parte primero
if hitPart.Parent then
explosion.Parent = Workspace
hitPart:Destroy() -- Destrúmpelo
end
end
end
end
-- Conecta la señal en serie inicialmente ya que cierto código de configuración no es capaz de ejecutarse en paralelo
remoteEventConnection = remoteEvent.OnServerEvent:Connect(onRemoteMouseEvent)
Generación de terreno procedural de lado del servidor
Para crear un mundo vasto para tu experiencia, puedes poblar el mundo de forma dinámica.La generación procedural crea típicamente bloques de terreno independientes, con el generador realizando cálculos relativamente intrincados para la colocación de objetos, el uso de materiales y el relleno de vóxeles.Ejecutar código de generación en paralelo puede mejorar la eficiencia del proceso.El siguiente ejemplo de código sirve como ejemplo.
-- La ejecución paralela requiere el uso de actores
-- Este script se clona a sí mismo; el original inicia el proceso, mientras que los clones actúan como trabajadores
local Workspace = game:GetService("Workspace")
local actor = script:GetActor()
if actor == nil then
local workers = {}
for i = 1, 32 do
local actor = Instance.new("Actor")
script:Clone().Parent = actor
table.insert(workers, actor)
end
-- Padre todos los actores bajo sí mismo
for _, actor in workers do
actor.Parent = script
end
-- Instruye a los actores para generar terreno enviando mensajes
-- En este ejemplo, los actores se eligen aleatoriamente
task.defer(function()
local rand = Random.new()
local seed = rand:NextNumber()
local sz = 10
for x = -sz, sz do
for y = -sz, sz do
for z = -sz, sz do
workers[rand:NextInteger(1, #workers)]:SendMessage("GenerateChunk", x, y, z, seed)
end
end
end
end)
-- Salida del script original; el resto del código se ejecuta en cada actor
return
end
function makeNdArray(numDim, size, elemValue)
if numDim == 0 then
return elemValue
end
local result = {}
for i = 1, size do
result[i] = makeNdArray(numDim - 1, size, elemValue)
end
return result
end
function generateVoxelsWithSeed(xd, yd, zd, seed)
local matEnums = {Enum.Material.CrackedLava, Enum.Material.Basalt, Enum.Material.Asphalt}
local materials = makeNdArray(3, 4, Enum.Material.CrackedLava)
local occupancy = makeNdArray(3, 4, 1)
local rand = Random.new()
for x = 0, 3 do
for y = 0, 3 do
for z = 0, 3 do
occupancy[x + 1][y + 1][z + 1] = math.noise(xd + 0.25 * x, yd + 0.25 * y, zd + 0.25 * z)
materials[x + 1][y + 1][z + 1] = matEnums[rand:NextInteger(1, #matEnums)]
end
end
end
return {materials = materials, occupancy = occupancy}
end
-- Vincular la llamada de devolución a ser llamada en contexto de ejecución paralela
actor:BindToMessageParallel("GenerateChunk", function(x, y, z, seed)
local voxels = generateVoxelsWithSeed(x, y, z, seed)
local corner = Vector3.new(x * 16, y * 16, z * 16)
-- Actualmente, WriteVoxels() debe llamarse en la fase serial
task.synchronize()
Workspace.Terrain:WriteVoxels(
Region3.new(corner, corner + Vector3.new(16, 16, 16)),
4,
voxels.materials,
voxels.occupancy
)
end)
Mejores prácticas
Para aplicar los máximos beneficios de la programación paralela, consulte las siguientes mejores prácticas al agregar su código Luau:
Evite las largas computaciones — Incluso en paralelo, las largas computaciones pueden bloquear la ejecución de otros scripts y causar retrasos.Evite usar programación paralela para manejar un gran volumen de cálculos largos e inflexibles.
Usa el número correcto de actores — Para el mejor ejecución, usa más Actors .Incluso si el dispositivo tiene menos núcleos que Actors, la granularidad permite un equilibrio de carga más eficiente entre los núcleos.
Esto no significa que deba usar tantos Actors como sea posible.Todavía deberías dividir el código en Actors según las unidades lógicas en lugar de romper el código con lógica conectada a diferentes Actors.Por ejemplo, si quieres habilitar la validación de raycasting en paralelo, es razonable usar 64 Actors y más en lugar de solo 4, incluso si estás apuntando a sistemas de cuatro núcleos.Esto es valioso para la escalabilidad del sistema y le permite distribuir el trabajo según la capacidad del hardware subyacente.Sin embargo, tampoco deberías usar demasiados Actors, que son difíciles de mantener.