Paralel Luau programlama modeliyle, deneyiminizin performansını geliştirebilecek birden fazla iş paralel olarak kod yürütebilirsiniz.Deneyiminizi daha fazla içerikle genişlettikçe, Luau betiklerinin performansını ve güvenliğini korumaya yardımcı olmak için bu modeli benimseyebilirsiniz.
Paralel programlama modeli
Varsayılan olarak, senaryolar sırayla çalışır.Deneyiminizin karmaşık mantığı veya içeriği varsa (örneğin, oyuncu olmayan karakterler (NPC), ışın atışı doğrulaması ve prosedürel oluşturma), ardışık çalışma kullanıcılarınız için gecikmelere neden olabilir.Paralel programlama modeliyle, görevleri çoklu senaryolara bölerek paralel çalıştırabilirsiniz ve bunları paralel olarak çalıştırabilirsiniz.Bu, deneyim kodunuzun daha hızlı çalışmasını sağlar, bu da kullanıcı deneyimini geliştirir.
Paralel programlama modeli ayrıca kodunuza güvenlik avantajları ekler.Kodu birden fazla iş parçasına bölerek, bir iş parçasında kodu düzenlerken, paralel olarak çalışan diğer kodları etkilemez.Bu, kodunuzdaki bir hata nedeniyle tüm deneyimi bozma riskini azaltır ve bir güncellemeyi ittiğinizde canlı sunuculardaki kullanıcılar için gecikmeyi azaltır.
Paralel programlama modelini benimsemek, her şeyi birden fazla iş parçasına yerleştirmek demek değildir.Örneğin, sunucu tarafı ışın atışı doğrulaması her bir kullanıcıya paralel olarak uzaktan bir etkinlik ayarlar, ancak hala global özellikleri değiştirmek için ilk kodun seri olarak çalışmasını gerektirir, ki bu paralel işlem için yaygın bir modeldir.
En çok kez, istediğiniz çıkıyı elde etmek için seri ve paralel fazları birleştirmeniz gerekir, çünkü şu anda paralel olarak desteklenmeyen bazı işlemler, örneğin paralel aşamalarda düzenlemeler yapmak gibi, senaryoların çalışmasını engelleyebilir.Paralel olarak API kullanım seviyesi hakkında daha fazla bilgi için, işlem güvenliği bölümüne bakın.
Kodu çok sayıda iş parçasına bölün
Deneyiminizin senaryolarını çoklu işlemlerde aynı anda çalıştırmak için, bunları veri modeli altındaki farklı aktörler arasında mantıksal parçalara ayırmanız gerekir.Aktörler, 'den miras alan örneklerle temsil edilir.Aynı anda çalışan birden fazla çekirdeğe yükü dağıtan bir infaz izolasyon birimi olarak çalışırlar.
Aktör örneklerini yerleştir
Aktörleri uygun kutulara yerleştirebilir veya NPC'ler ve ışın atıcılar gibi 3B varlıkların üst düzey örnek türlerini değiştirmek için kullanabilir ve ardından ilgili senaryoları ekleyebilirsiniz.

Çoğu durumda, bir aktörü diğer bir aktörün çocuğu olarak veri modeline yerleştirmemelisiniz.Ancak, belirli kullanım durumunuz için birden fazla aktör içine yerleştirilmiş bir senaryo yerleştirmeye karar verirseniz, senaryo en yakın atası aktörü tarafından sahiptir.

İplikleri senkronize etmeyi bırak Desynchronize threads
Senaryoları aktörlerin altına yerleştirmek onlara paralel çalışma yeteneği verir, ancak varsayılan olarak kod hala tek bir iş parçacığı üzerinde seri olarak çalışır, ki bu da çalışma sözleşme imzalamageliştirmez.Kod yürütümünü paralel olarak çalıştırmak ve bunu bir sonraki paralel yürütme fırsatında yeniden başlatmak için çalıştırılabilir task.desynchronize() fonksiyonunu çağırmalısınız, böylece mevcut koreutinin yürütmesi askıya alınır ve bir sonraki paralel yürütme fırsatında yeniden başlatılır.Bir senaryoyu seri yürütüme geri döndürmek için, task.synchronize() 'yi arayın.
Alternatif olarak, bir sinyal geri çağrısını planlamak istediğinizde RBXScriptSignal:ConnectParallel() yöntemini kullanarak kodunuzu tetikte olduğunda hemen paralel çalıştırabilirsiniz.Sinyal geri çağrısı içinde task.desynchronize() çağırmak zorunda değilsiniz.
Bir İpucunun Senkronizasyonunu Kaldır
local RunService = game:GetService("RunService")
RunService.Heartbeat:ConnectParallel(function()
... -- Bir durum güncellemesi hesaplayan bazı paralel kod
task.synchronize()
... -- Instansların durumunu değiştiren bazı seri kodlar
end)
Aynı aktörün parçası olan senaryolar daima birbirine göre sırayla yürütülür, bu yüzden çok sayıda aktöre ihtiyacınız var.Örneğin, NPC'niz için tüm paralel etkin davranış senaryolarını bir aktöre yerleştirirseniz, hala tek bir iş parçası üzerinde seri olarak çalışırlar, ancak farklı NPC mantığı için çok sayıda aktörünüz varsa, her biri kendi iş parçası üzerinde paralel olarak çalışır.Daha fazla bilgi için, En iyi uygulamalar görün.


İpucu güvenliği
Paralel çalışma sırasında, DataModel hierarşisinin çoğu istisnasız olarak erişebilirsiniz, ancak bazı API özellikleri ve işlevleri okumak veya yazmak için güvenli değildir.Paralel kodunuzda kullanırsanız, Roblox Motoru bu erişimlerin otomatik olarak tespit edilmesini ve önlenmesini sağlayabilir.
API üyelerinin bir iş parçacığı güvenlik seviyesi vardır ve aşağıdaki tablo gösterdiği gibi paralel kodunuzda onları nasıl ve ne zaman kullanabileceğinizi gösterir:
Güvenlik seviyesi | Özellikler için | Fonksiyonlar için |
---|---|---|
Güvensiz | Paralel olarak okunamaz veya yazılamaz. | Paralel olarak çağrılamaz. |
Paralel Okuyun | Okuyabilir ancak paralel olarak yazılamaz. | N/A |
Yerel Güvenlik | Aynı Aktör içinde kullanılabilir; paralel olarak diğer Actors tarafından okunabilir ancak yazılamaz. | Aynı Aktör içinde çağrılabilir; paralel olarak diğer Actors tarafından çağrılamaz. |
Güvenli | Okuyup yazılabilir. | Çağrılabilir. |
API üyeleri için işaret güvenliği etiketlerini API referansı üzerinde bulabilirsiniz.Onları kullanırken, API çağrılarının veya özellik değişikliklerinin paralel işlemler arasında nasıl etkileşebileceğini de düşünmelisiniz.Genellikle, çok sayıda aktör aynı verileri diğer aktörlerle okuyabilir, ancak diğer aktörlerin durumunu değiştirmez.
Çapraz işletim kolu iletişimi
Çok işlevli bağlam altında, farklı aktörlerdeki kodların birbiriyle iletişim kurarak veri değiştirmek, görevleri koordine etmek ve aktiviteleri senkronize etmek için hala izin verebilirsiniz.Motor, çapraz işletim iletişimi için aşağıdaki mekanizmaları destekler:
- Aktör mesajlaşması Aktörlere senaryolar kullanarak mesaj göndermek için bir aktör mesajlaşma API'si.
- Paylaşılan masa paylaşılan bir durumda çok sayıda veri arasında verimli bir şekilde paylaşmak için paylaşılan tablo veri yapısı.
- Doğrudan veri modeli iletişimi kısıtlı iletişim için basit.
Çapraz işletim iletişim ihtiyaçlarınızı karşılamak için çok sayıda mekanizmayı destekleyebilirsiniz.Örneğin, Aktör Mesajlaşma API üzerinden paylaşılan bir tablo gönderebilirsiniz.
Aktör mesajlaşması
Aktör mesajlaşması API'si, bir senaryoda veya paralel bir bağlamda bir aktöre aynı veri modelinde veri göndermeyi sağlar.Bu API aracılığıyla iletişim asenkron değildir, yani gönderen alıcı mesajı alana kadar bloke etmez.
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 içeride bir mesaja bağlı çok sayıda geri çağrıya sahip olabilir.Sadece aktörün soyundan gelen yazılımlar mesaj alabilir.
API'nin aşağıdaki yöntemleri vardır:
- Actor:SendMessage() bir aktöre mesaj göndermek için.
- Actor:BindToMessage() bir dizi bağlantı noktasındaki belirtilen konuyla bir Luau geri çağrısını bir mesaja bağlamak için.
- Actor:BindToMessageParallel() bir Luau geri çağrısını paralel bir bağlamda belirtilen konuyla bir mesaja bağlamak için.
Aşağıdaki örnek, bir konuyu tanımlamak ve gönderen tarafından bir mesaj göndermek için Actor:SendMessage() nasıl kullanılacağını gösterir:
Mesaj Göndericisi Örneği
local Workspace = game:GetService("Workspace")-- Bir "Selamlama" konusuyla işçi aktöre iki mesaj gönderlocal workerActor = Workspace.WorkerActorworkerActor:SendMessage("Greeting", "Hello World!")workerActor:SendMessage("Greeting", "Welcome")print("Sent messages")
Aşağıdaki örnek, alıcı tarafındaki paralel bir bağlantı için belirli bir konu için geri çağrı bağlamak için Actor:BindToMessageParallel() nasıl kullanılacağını gösterir:
Mesaj Alıcı Örneği
-- Bu senaryonun ebeveyn olduğu aktörü alın
local actor = script:GetActor()
-- Selamlama" mesaj konusu için bir geri arama bağlayın
actor:BindToMessageParallel("Greeting", function(greetingString)
print(actor.Name, "-", greetingString)
end)
print("Bound to messages")
Paylaşılan tablo
SharedTable birden fazla aktör altında çalışan senaryolardan erişilebilen tablo benzeri bir veri yapısıdır.Büyük miktarda veri içeren durumlar ve çok sayıda işletme arasında ortak bir paylaşılan durum gerektiren durumlar için yararlıdır.Örneğin, birden fazla aktör, veri modeline depolanmayan ortak bir dünya durumunda çalışırken.
Paylaşılan bir tabloyu başka bir aktöre göndermek verilerin bir kopyasını oluşturmaz.Bunun yerine, paylaşılan tablolar aynı anda birden fazla yazılım tarafından güvenli ve atomik güncellemeler sağlar.Bir aktör tarafından paylaşılan tabloya yapılan her güncelleme hemen tüm aktörler tarafından görülebilir.Paylaşılan tablolar ayrıca temel verileri kopyalamak yerine yapısal paylaşımı kullanan kaynak verimli bir süreçte klonlanabilir.
Doğrudan veri modeli iletişimi
Ayrıca, farklı aktörlerin özellikleri veya öznitelikleri yazıp daha sonra okuyabileceği veri modelini kullanarak doğrudan çok sayıda işletme arasındaki iletişimi kolaylaştırabilirsiniz, böylece farklı aktörler birbirleriyle iletişim kurabilir ve birbirlerini takip edebilir.Ancak, çekirdek güvenliğini korumak için, paralel olarak çalışan kodlar genellikle veri modeline yazamaz.Bu nedenle, iletişim için veri modelini doğrudan kullanmak kısıtlamalarla gelir ve kodların sık sık senkronize edilmesini zorlayabilir, ki bu da senaryolarınızın performansını etkileyebilir.
Örnekler
Sunucu tarafı ışın atışı doğrulaması
Savaş ve savaş deneyimi için, kullanıcıların silahları için ışın atışı etkinleştirmeniz gerekir.Müşteri, iyi bir gecikme elde etmek için silahları simüle ederek, sunucu vuruşu onaylamak zorundadır, ki bununla raycast'lar ve beklenen karakter hızını hesaplayan bazı heuristikler yapılır ve geçmiş davranışlara bakılır.
Müşterilerin hit bilgilerini iletmek için kullandığı uzaktaki bir olaya bağlanan tek merkezi senaryoyu kullanmak yerine, her kullanıcı karakterinin ayrı bir uzak olaya sahip olmasıyla paralel olarak sunucu tarafında her bir hit doğrulama süreci çalıştırabilirsiniz.
Bu karakterin Actor altında çalışan sunucu tarafı kodu, vuruşu onaylamak için ilgili mantığı çalıştırmak için paralel bir bağlantı kullanarak bu uzak olaya bağlanır.Mantık bir vuruşun doğrulanmasını bulursa, hasar azaltılır, bu da özellikleri değiştirmeyi içerir, bu nedenle başlangıçta seri olarak çalışır.
local Workspace = game:GetService("Workspace")
local tool = script.Parent.Parent
local remoteEvent = Instance.new("RemoteEvent") -- Yeni uzaktan etkinlik oluştur ve araçla eşleştir
remoteEvent.Name = "RemoteMouseEvent" -- Yerel kodun onu arayabilmesi için yeniden adlandırın
remoteEvent.Parent = tool
local remoteEventConnection -- Uzaktaki etkinlik bağlantısı için bir referans oluştur
-- Uzaktaki bir olayı dinleyen işlev
local function onRemoteMouseEvent(player: Player, clickLocation: CFrame)
-- SERIAL: Kurulum kodunu seri olarak çalıştır
local character = player.Character
-- Işın atarken kullanıcının karakterini görmezden gel
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { character }
-- PARALEL: Işınları paralel yapın
task.desynchronize()
local origin = tool.Handle.CFrame.Position
local epsilon = 0.01 -- Tıklama konumundan nesneye biraz sapma olabileceğinden, ışını biraz genişletmek 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")
-- SERIAL: Aşağıdaki kod, aktörün dışındaki durumu değiştirir
task.synchronize()
explosion.DestroyJointRadiusPercent = 0 -- Patlamayı ölümcül olmayan yap
explosion.Position = clickLocation.Position
-- Birden fazla aktör bir ışın atışında aynı parçayı alabilir ve onu yok etmeye karar verebilir
-- Bu mükemmel derecede güvenlidir, ancak bir kez yerine iki patlama gerçekleşecektir
-- Aşağıdaki çifte kontroller ilk önce bu kısma yürütmenin ulaşmasını sağlar
if hitPart.Parent then
explosion.Parent = Workspace
hitPart:Destroy() -- Yok edin
end
end
end
end
-- Başlangıçta seri olarak sinyali bağlayın, çünkü bazı kurulum kodları paralel olarak çalışamıyor
remoteEventConnection = remoteEvent.OnServerEvent:Connect(onRemoteMouseEvent)
Sunucu tarafı prosedürel arazi oluşturma
Deneyiminiz için geniş bir dünya oluşturmak için, dünyayı dinamik olarak doldurabilirsiniz.Prosedürel oluşturma genellikle bağımsız arazi parçaları oluşturur, jeneratör nesne yerleştirme, malzeme kullanımı ve voksel doldurma için nispeten karmaşık hesaplamalar yapar.Paralel olarak nesil kodunu çalıştırmak, sürecin verimliliğini artırabilir.Aşağıdaki kod örneği bir örnek olarak hizmet eder.
-- Paralel yürütme aktörlerin kullanılmasını gerektirir
-- Bu senaryo kendini klonlar; orijinal süreci başlatırken, klonlar işçi olarak davranır
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
-- Kendi altındaki tüm aktörleri ebeveyn yap
for _, actor in workers do
actor.Parent = script
end
-- Aktörlere mesaj göndererek arazi oluşturmalarını talimat verin
-- 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 senaryodan çıkış; kodun geri kalanı 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 konteksinde çağrılacak geri çağrıyı bağlayın
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() seri fazda ç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ı uygulamak için, Luau kodunuzu eklerken aşağıdaki en iyi uygulamalara göz atın:
Uzun hesaplamalardan kaçının — Paralel bile olsa, uzun hesaplamalar diğer kodların yürütümünü engelleyebilir ve gecikmelere neden olabilir.Uzun ve teslim olmayan hesapların büyük bir hacmini ele almak için paralel programlama kullanımından kaçının.
Doğru Aktör Sayısını Kullanın — En iyi sözleşme imzalamaiçin daha fazla Actors.Cihazın Actors daha az çekirdeğe sahip olması durumunda bile, granülarite çekirdekler arasında daha verimli yük dengeleme sağlar.
Bu, mümkün olduğunca çok Actors kullanmanız gerektiği anlamına gelmez.Kodu hala mantık birimlerine göre Actors bölmeli ve bağlı mantık ile farklı Actors koda kırmak yerine mantık birimlerine göre bölmelisiniz.Örneğin, eğer paralel olarak ışın atışı doğrulamasını etkinleştirmek istiyorsanız , sadece 4 hedef aldığınız halde 64 ve daha fazlasını kullanmak mantıklıdır, 4 çekirdekli sistemlere hedef olsa bile.Bu, sistemin ölçeklenebilirliği için değerlidir ve temel donanımın yeteneklerine dayalı olarak çalışmayı dağıtmasına izin verir.Ancak, ayrıca çok fazla Actors kullanmamalısınız, ki bunları korumak zordur.