Paralel Luau

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Paralel Luau programlama modeli ile kodu birden fazla iş parçacığında aynı anda çalıştırabilirsiniz, bu da oyununuzun performansını artırabilir. Oyununuza daha fazla içerik ekledikçe, Luau betiklerinizin performansını ve güvenliğini korumaya yardımcı olmak için bu modeli benimseyebilirsiniz.

Paralel programlama modeli

Varsayılan olarak, betikler sıralı olarak çalışır. Oyununuza karmaşık mantık veya içerik eklediyseniz, örneğin oyuncu olmayan karakterler (NPC'ler), ışın izleme doğrulaması ve prosedürel üretim gibi, sıralı yürütme kullanıcılarınız için gecikmelere neden olabilir. Paralel programlama modeli ile görevleri birden fazla betiğe ayırabilir ve bunları paralel olarak çalıştırabilirsiniz. Bu, oyun kodunuzun daha hızlı çalışmasını sağlar ve kullanıcı deneyimini iyileştirir.

Paralel programlama modeli ayrıca kodunuza güvenlik avantajları ekler. Kodu birden fazla iş parçacığına ayırarak, bir iş parçacığında kodu düzenlediğinizde, bu durum paralel olarak çalışan diğer kodları etkilemez. Bu, kodunuzda bir hatanın tüm oyunu bozma riskini azaltır ve güncellemeleri canlı sunucularda kullanıcılar için gecikmeyi en aza indirir.

Paralel programlama modelini benimsemek, her şeyi birden fazla iş parçacığına koymak anlamına gelmez. Örneğin, sunucu tarafı ışın izleme doğrulaması, her bir kullanıcıya paralel olarak bir uzaktan olay ayarlarken, yine de küresel özellikleri değiştirmek için başlangıç kodunun sıralı olarak çalışmasını gerektirir; bu, paralel yürütme için yaygın bir kalıptır.

Çoğu zaman, istediğiniz çıktıyı elde etmek için sıralı ve paralel aşamaları birleştirmeniz gerekir, çünkü şu anda paralel olarak desteklenmeyen bazı işlemler, betiklerin çalışmasını engelleyebilir, örneğin paralel aşamalarda örnekleri değiştirmek gibi. Paralel kullanımda API'lerin kullanım düzeyi hakkında daha fazla bilgi için iş parçacığı güvenliği bölümüne bakın.

Kodu birden fazla iş parçacığına ayırma

Oyununuza ait betikleri birden fazla iş parçacığında eşzamanlı olarak çalıştırmak için, bunları veri modelinde farklı aktörler altında mantıksal parçalara ayırmanız gerekir. Aktörler, DataModel'dan miras alan Actor örnekleri ile temsil edilir. Bunlar, yükü birden fazla çekirdeğe dağıtan yürütme izolasyonu birimleri olarak çalışır.

Aktör örneklerini yerleştirme

Aktörleri uygun konteynerlere yerleştirebilir veya bunları NPC'ler ve ışın izleyiciler gibi 3D varlıklarınızın üst düzey örnek türlerini değiştirmek için kullanabilir, ardından ilgili betikleri ekleyebilirsiniz.

Bir Aktör altındaki bir Betik örneği

Çoğu durumda, bir aktörü veri modelinde başka bir aktörün çocuğu olarak yerleştirmemelisiniz. Ancak, belirli bir kullanım durumunuz için bir betiği birden fazla aktörün içinde yerleştirmeye karar verirseniz, betik en yakın ata aktörüne aittir.

Bir betiğin en yakın aktör tarafından nasıl sahiplenildiğini gösteren aktörler ve betikler ağacı

İş parçacıklarını senkronize etmeme

Betikleri aktörlerin altında yerleştirmek, onlara paralel yürütme yeteneği kazandırsa da, varsayılan olarak kod hala tek bir iş parçacığında sıralı olarak çalışır, bu da çalışma zamanı performansını artırmaz. task.desynchronize() çağrısını yapmanız gerekir; bu, mevcut korutinin yürütmesini askıya alan ve kodu paralel olarak çalıştırmak için bir fırsat geldiğinde yeniden başlatan bir yieldable işlevdir. Bir betiği tekrar sıralı yürütmeye geçirmek için task.synchronize() çağrısını yapın.

Alternatif olarak, bir sinyal geri çağrısını tetiklenir tetiklenmez paralel olarak çalıştırmak için RBXScriptSignal:ConnectParallel() yöntemini kullanabilirsiniz. Sinyal geri çağrısı içinde task.desynchronize() çağrısını yapmanıza gerek yoktur.

Bir İş Parçacığını Senkronize Etme
local RunService = game:GetService("RunService")
RunService.Heartbeat:ConnectParallel(function()
... -- Bir durum güncellemesi hesaplayan bazı paralel kod
task.synchronize()
... -- Örneklerin durumunu değiştiren bazı sıralı kod
end)

Aynı aktörün bir parçası olan betikler her zaman birbirlerine karşı sıralı olarak çalışır, bu nedenle birden fazla aktöre ihtiyacınız vardır. Örneğin, NPC'niz için tüm paralel etkinlik betiklerini bir aktörde toplarsanız, yine de tek bir iş parçacığında sıralı olarak çalışırlar, ancak farklı NPC mantıkları için birden fazla aktörünüz varsa, her biri kendi iş parçacığında paralel olarak çalışır. Daha fazla bilgi için En iyi uygulamalar bölümüne bakın.

Aktörlerdeki paralel kodun tek bir iş parçacığında sıralı olarak çalışması
Aktörlerdeki paralel kodun birden fazla iş parçacığında aynı anda çalışması

İş parçacığı güvenliği

Paralel yürütme sırasında, DataModel hiyerarşisinin çoğu örneğine normal şekilde erişebilirsiniz, ancak bazı API özellikleri ve işlevleri okunması veya yazılması güvenli değildir. Eğer bunları paralel kodunuzda kullanırsanız, Roblox motoru bu erişimleri otomatik olarak tespit edip engelleyebilir.

API üyelerinin bir iş parçacığı güvenliği seviyesi vardır; bu seviye, bunları paralel kodunuzda nasıl kullanabileceğinizi gösterir. Aşağıdaki tablo bunu göstermektedir:

Güvenlik seviyesiÖzellikler içinİşlevler için
GüvensizParalel olarak okunamaz veya yazılamaz.Paralel olarak çağrılamaz.
Paralel OkumaParalel olarak okunabilir ancak yazılamaz.N/A
Yerel GüvenliAynı Aktör içinde kullanılabilir; diğer Actors tarafından paralel olarak okunamaz ancak yazılabilir.Aynı Aktör içinde çağrılabilir; diğer Actors tarafından paralel olarak çağrılamaz.
GüvenliOkunabilir ve yazılabilir.Çağrılabilir.

API üyeleri için iş parçacığı güvenliği etiketlerini API referansında bulabilirsiniz. Bunları kullanırken, API çağrılarının veya özellik değişikliklerinin paralel iş parçacıkları arasında nasıl etkileşime girebileceğini de göz önünde bulundurmalısınız. Genellikle, birden fazla aktörün aynı veriyi okuması güvenlidir, ancak diğer aktörlerin durumunu değiştirmesi güvenli değildir.

İş parçacıkları arası iletişim

Çoklu iş parçacığı bağlamında, farklı aktörlerdeki betiklerin birbirleriyle iletişim kurmasına, veri alışverişi yapmasına, görevleri koordine etmesine ve etkinlikleri senkronize etmesine izin verebilirsiniz. Motor, iş parçacıkları arası iletişim için aşağıdaki mekanizmaları destekler:

İş parçacıkları arası iletişim ihtiyaçlarınızı karşılamak için birden fazla mekanizmayı destekleyebilirsiniz. Örneğin, Aktör Mesajlaşma API'si aracılığıyla bir paylaşılan tablo gönderebilirsiniz.

Aktör mesajlaşma

Aktör mesajlaşma API'si, bir betiğin, sıralı veya paralel bir bağlamda, aynı veri modelindeki bir aktöre veri göndermesine olanak tanır. Bu API aracılığıyla iletişim asenkron olup, gönderici mesaj alıcı tarafından alınana kadar engellenmez.

Bu API'yi kullanarak mesaj gönderirken, mesajı kategorize etmek için bir konu tanımlamanız gerekir. Her mesaj yalnızca bir aktöre gönderilebilir, ancak o aktör, bir mesaja bağlı birden fazla geri çağrıyı içerebilir. Yalnızca bir aktörün alt öğeleri olan betikler mesaj alabilir.

API'nin aşağıdaki yöntemleri vardır:

Aşağıdaki örnek, Actor:SendMessage() kullanarak bir konu tanımlamayı ve gönderici tarafında bir mesaj göndermeyi göstermektedir:

Örnek Mesaj Gönderici
local Workspace = game:GetService("Workspace")
-- "Selamlaşma" konusuyla işçi aktörüne iki mesaj gönder
local workerActor = Workspace.WorkerActor
workerActor:SendMessage("Greeting", "Merhaba Dünya!")
workerActor:SendMessage("Greeting", "Hoş geldiniz")
print("Mesajlar gönderildi")

Aşağıdaki örnek, Actor:BindToMessageParallel() kullanarak alıcı tarafında belirli bir konu için bir geri çağrıyı paralel bir bağlamda bağlamayı göstermektedir:

Örnek Mesaj Alıcı
-- Bu betiğin ait olduğu aktörü al
local actor = script:GetActor()
-- "Selamlaşma" mesaj konusu için bir geri çağrıyı bağla
actor:BindToMessageParallel("Greeting", function(greetingString)
print(actor.Name, "-", greetingString)
end)
print("Mesajlara bağlandı")

Paylaşılan tablo

SharedTable, birden fazla aktör altında çalışan betiklerden erişilebilen tablo benzeri bir veri yapısıdır. Bu, büyük miktarda veri içeren ve birden fazla iş parçacığı arasında ortak bir paylaşılan duruma ihtiyaç duyan durumlar için kullanışlıdır. Örneğin, birden fazla aktörün veri modelinde saklanmayan ortak bir dünya durumunda çalışması gerektiğinde.

Bir paylaşılan tabloyu başka bir aktöre göndermek, verinin bir kopyasını oluşturmaz. Bunun yerine, paylaşılan tablolar, birden fazla betik tarafından aynı anda güvenli ve atomik güncellemeler yapılmasına olanak tanır. Bir aktör tarafından yapılan her güncelleme, tüm aktörler için hemen görünür. Paylaşılan tablolar, temel veriyi kopyalamak yerine yapısal paylaşım kullanan kaynak verimli bir süreçte de kopyalanabilir.

Doğrudan veri modeli iletişimi

Ayrıca, farklı aktörlerin özellikleri veya nitelikleri yazmasına ve ardından okumasına olanak tanıyarak, birden fazla iş parçacığı arasında doğrudan iletişimi kolaylaştırabilirsiniz. Ancak, iş parçacığı güvenliğini korumak için, paralel olarak çalışan betikler genellikle veri modeline yazamaz. Bu nedenle, iletişim için veri modelini doğrudan kullanmak kısıtlamalarla birlikte gelir ve betikleri sık sık senkronize etmeye zorlayabilir, bu da betiklerinizin performansını etkileyebilir.

Örnekler

Sunucu tarafı ışın izleme doğrulaması

Bir dövüş ve savaş oyunu için, kullanıcılarınızın silahları için ışın izlemeyi etkinleştirmeniz gerekir. İyi bir gecikme sağlamak için istemcinin silahları simüle etmesi gerekir, sunucunun ise vurmayı doğrulaması gerekir; bu, ışın izlemeleri yapmayı ve beklenen karakter hızını hesaplayan bazı sezgisel işlemleri içerir ve geçmiş davranışa bakar.

Müşterilerin vurma bilgilerini iletmek için kullandığı bir uzaktan olaya bağlanan tek bir merkezi betik kullanmak yerine, her bir kullanıcı karakterinin ayrı bir uzaktan olaya sahip olduğu sunucu tarafında her vurma doğrulama sürecini paralel olarak çalıştırabilirsiniz.

O karakterin Actor'ı altında çalışan sunucu tarafı betiği, vurmayı doğrulamak için ilgili mantığı çalıştırmak üzere bu uzaktan olaya paralel bir bağlantı ile bağlanır. Mantık bir vurma onayı bulursa, hasar düşülür; bu, özellikleri değiştirmeyi içerir, bu nedenle başlangıçta sıralı olarak çalışır.

local Workspace = game:GetService("Workspace")
local tool = script.Parent.Parent
local remoteEvent = Instance.new("RemoteEvent") -- Yeni bir uzaktan olay oluştur ve araca ekle
remoteEvent.Name = "RemoteMouseEvent" -- Yerel betiğin bunu arayabilmesi için yeniden adlandır
remoteEvent.Parent = tool
local remoteEventConnection -- Uzaktan olay bağlantısı için bir referans oluştur
-- Bir uzaktan olayı dinleyen işlev
local function onRemoteMouseEvent(player: Player, clickLocation: CFrame)
-- Sıralı: Sıralı olarak kurulum kodunu çalıştır
local character = player.Character
-- Işın izleme sırasında kullanıcının karakterini göz ardı et
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { character }
-- Paralel: Işın izlemeyi paralel olarak gerçekleştir
task.desynchronize()
local origin = tool.Handle.CFrame.Position
local epsilon = 0.01 -- Tıklama konumu nesneden biraz kaymış olabileceğinden ışını biraz uzatmak için kullanılır
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")
-- Sıralı: Aşağıdaki kod, aktör dışındaki durumu değiştirir
task.synchronize()
explosion.DestroyJointRadiusPercent = 0 -- Patlamayı öldürücü yapma
explosion.Position = clickLocation.Position
-- Birden fazla aktör, bir ışın izleme sırasında aynı parçayı alabilir ve yok etmeye karar verebilir
-- Bu tamamen güvenlidir ama bir yerine iki patlama olmasına neden olur
-- Aşağıdaki kontrol, yürütmenin önce bu parçaya ulaştığını doğrular
if hitPart.Parent then
explosion.Parent = Workspace
hitPart:Destroy() -- Yok et
end
end
end
end
-- Başlangıçta bazı kurulum kodları paralel olarak çalışamayacağından sinyali sıralı olarak bağla
remoteEventConnection = remoteEvent.OnServerEvent:Connect(onRemoteMouseEvent)

Sunucu tarafı prosedürel arazi oluşturma

Oyununuza geniş bir dünya oluşturmak için, dünyayı dinamik olarak doldurabilirsiniz. Prosedürel üretim genellikle bağımsız arazi parçaları oluşturur; üretici, nesne yerleştirme, malzeme kullanımı ve voxel doldurma için nispeten karmaşık hesaplamalar yapar. Üretim kodunu paralel olarak çalıştırmak, sürecin verimliliğini artırabilir. Aşağıdaki kod örneği bir örnek olarak hizmet etmektedir.

-- Paralel yürütme, aktörlerin kullanılmasını gerektirir
-- Bu betik kendini kopyalar; orijinal süreci başlatır, kopyalar ise işçi olarak hareket eder
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
-- Tüm aktörleri kendisinin altına yerleştir
for _, actor in workers do
actor.Parent = script
end
-- Aktörlere mesaj göndererek arazi oluşturmalarını talimat ver
-- Bu örnekte, aktörler rastgele seçilir
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)
-- Orijinal betikten çık; geri kalan kod her aktörde çalışır
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
-- Paralel yürütme bağlamında çağrılacak geri çağrıyı bağla
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)
-- Şu anda, WriteVoxels() sıralı aşamada çağrılmalıdır
task.synchronize()
Workspace.Terrain:WriteVoxels(
Region3.new(corner, corner + Vector3.new(16, 16, 16)),
4,
voxels.materials,
voxels.occupancy
)
end)

En iyi uygulamalar

Paralel programlamanın maksimum faydalarını sağlamak için, Luau kodunuzu eklerken aşağıdaki en iyi uygulamalara başvurun:

  • Uzun Hesaplamalardan Kaçının — Paralel olsa bile, uzun hesaplamalar diğer betiklerin yürütmesini engelleyebilir ve gecikmelere neden olabilir. Uzun, yield etmeyen hesaplamaları ele almak için paralel programlamayı kullanmaktan kaçının.

    Paralel yürütme aşamasını aşırı yüklemenin hala gecikmelere neden olabileceğini gösteren diyagram
  • Doğru Sayıda Aktör Kullanın — En iyi performans için daha fazla Actors kullanın. Cihazın Actors'dan daha az çekirdeği olsa bile, ayrıntı, çekirdekler arasında daha verimli yük dengelemesi sağlar.

    Daha fazla aktör kullanmanın yükü çekirdekler arasında nasıl dengelediğini gösteren gösterim

    Bu, mümkün olduğunca fazla Actors kullanmanız gerektiği anlamına gelmez. Hala kodu, bağlı mantığa göre Actors'a bölmelisiniz, farklı Actors'a bağlı mantığı kırmamalısınız. Örneğin, paralel olarak ışın izleme doğrulamasını etkinleştirmek istiyorsanız, 4 çekirdekli sistemleri hedefleseniz bile 64 Actors ve daha fazlasını kullanmak mantıklıdır. Bu, sistemin ölçeklenebilirliği için değerlidir ve temel donanımın yeteneklerine göre işi dağıtmasına olanak tanır. Ancak, çok fazla Actors kullanmamalısınız, çünkü bunlar bakımı zor hale getirir.

©2026 Roblox Corporation. Roblox, the Roblox logo and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.