Luau Paralel

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Dengan model pemrograman Luau Paralel, Anda dapat menjalankan kode di beberapa utas secara bersamaan, yang dapat meningkatkan kinerja pengalaman Anda. Ketika Anda memperluas pengalaman Anda dengan lebih banyak konten, Anda dapat mengadopsi model ini untuk membantu mempertahankan kinerja dan keamanan skrip Luau Anda.

Model pemrograman paralel

Secara default, skrip dieksekusi secara berurutan. Jika pengalaman Anda memiliki logika atau konten yang kompleks, seperti karakter non-pemain (NPC), validasi raycasting, dan generasi prosedural, maka eksekusi berurutan dapat menyebabkan lag bagi pengguna Anda. Dengan model pemrograman paralel, Anda dapat memecah tugas menjadi beberapa skrip dan menjalankannya secara paralel. Ini membuat kode pengalaman Anda berjalan lebih cepat, yang meningkatkan pengalaman pengguna.

Model pemrograman paralel juga menambahkan manfaat keamanan pada kode Anda. Dengan memecah kode menjadi beberapa utas, ketika Anda mengedit kode di satu utas, itu tidak mempengaruhi kode lain yang berjalan secara paralel. Ini mengurangi risiko memiliki satu bug dalam kode Anda yang merusak seluruh pengalaman, dan meminimalkan penundaan bagi pengguna di server langsung ketika Anda mengeluarkan pembaruan.

Mengadopsi model pemrograman paralel tidak berarti menempatkan semua kode dalam beberapa utas. Sebagai contoh, validasi raycasting sisi server mengatur setiap pengguna individu dengan suatu event jarak jauh secara paralel tetapi masih memerlukan kode awal untuk dijalankan secara berurutan untuk mengubah properti global, yang merupakan pola umum untuk eksekusi paralel.

Kebanyakan waktu, Anda perlu menggabungkan fase serial dan paralel untuk mencapai output yang diinginkan, karena saat ini ada beberapa operasi yang tidak didukung secara paralel yang dapat mencegah skrip berjalan, seperti memodifikasi instansi dalam fase paralel. Untuk informasi lebih lanjut tentang tingkat penggunaan API dalam paralel, lihat keamanan utas.

Memecah kode menjadi beberapa utas

Untuk menjalankan skrip pengalaman Anda dalam beberapa utas secara bersamaan, Anda perlu memecahnya menjadi bagian-bagian logis di bawah aktor yang berbeda dalam model data. Aktor diwakili oleh instansi Actor yang diwarisi dari DataModel. Mereka berfungsi sebagai unit isolasi eksekusi yang mendistribusikan beban di beberapa inti yang berjalan secara bersamaan.

Tempatkan instansi aktor

Anda dapat menempatkan aktor di wadah yang sesuai atau menggunakannya untuk menggantikan tipe instansi level atas dari entitas 3D Anda seperti NPC dan raycaster, kemudian tambahkan skrip yang sesuai.

Contoh Skrip di bawah Aktor

Untuk sebagian besar situasi, Anda sebaiknya tidak menempatkan aktor sebagai anak dari aktor lain dalam model data. Namun, jika Anda memutuskan untuk menempatkan skrip yang terpendam di dalam beberapa aktor untuk kasus penggunaan spesifik Anda, skrip tersebut dimiliki oleh aktor nenek moyangnya yang terdekat.

Pohon aktor dan skrip yang menunjukkan bagaimana skrip dimiliki oleh aktor terdekatnya

Desinkronisasi utas

Meskipun menempatkan skrip di bawah aktor memberikan mereka kemampuan untuk eksekusi paralel, secara default kode masih berjalan dalam satu utas secara berurutan, yang tidak meningkatkan kinerja runtime. Anda perlu memanggil task.desynchronize(), sebuah fungsi yang dapat ditunda yang menghentikan eksekusi coroutine saat ini untuk menjalankan kode secara paralel dan melanjutkannya pada kesempatan eksekusi paralel berikutnya. Untuk mengalihkan skrip kembali ke eksekusi berurutan, panggil task.synchronize().

Sebagai alternatif, Anda dapat menggunakan metode RBXScriptSignal:ConnectParallel() ketika Anda ingin menjadwalkan callback sinyal untuk segera menjalankan kode Anda secara paralel saat dipicu. Anda tidak perlu memanggil task.desynchronize() di dalam callback sinyal.

Desinkronisasi Sebuah Utas

local RunService = game:GetService("RunService")
RunService.Heartbeat:ConnectParallel(function()
... -- Beberapa kode paralel yang menghitung pembaruan status
task.synchronize()
... -- Beberapa kode serial yang mengubah status instansi
end)

Skrip yang merupakan bagian dari aktor yang sama selalu dieksekusi secara berurutan satu sama lain, jadi Anda perlu beberapa aktor. Sebagai contoh, jika Anda menempatkan semua skrip perilaku yang diaktifkan paralel untuk NPC Anda dalam satu aktor, mereka masih berjalan secara serial dalam satu utas, tetapi jika Anda memiliki beberapa aktor untuk logika NPC yang berbeda, masing-masing dari mereka berjalan secara paralel di utasnya sendiri. Untuk informasi lebih lanjut, lihat Praktik terbaik.

Kode paralel dalam Aktor yang berjalan secara serial dalam satu utas
Kode paralel dalam Aktor yang berjalan secara bersamaan dalam beberapa utas

Keamanan utas

Selama eksekusi paralel, Anda bisa mengakses sebagian besar instansi dari hierarki DataModel seperti biasa, tetapi beberapa properti dan fungsi API tidak aman untuk dibaca atau ditulis. Jika Anda menggunakannya dalam kode paralel Anda, mesin Roblox dapat secara otomatis mendeteksi dan mencegah akses ini terjadi.

Anggota API memiliki tingkat keamanan utas yang menunjukkan apakah dan bagaimana Anda dapat menggunakannya dalam kode paralel Anda, seperti yang ditunjukkan pada tabel berikut:

Tingkat keamananUntuk propertiUntuk fungsi
Tidak AmanTidak dapat dibaca atau ditulis secara paralel.Tidak dapat dipanggil secara paralel.
Baca ParalelDapat dibaca tetapi tidak ditulis secara paralel.T/A
Aman LokalDapat digunakan dalam Aktor yang sama; dapat dibaca tetapi tidak ditulis oleh Aktor lain secara paralel.Dapat dipanggil dalam Aktor yang sama; tidak dapat dipanggil oleh Aktor lain secara paralel.
AmanDapat dibaca dan ditulis.Dapat dipanggil.

Anda dapat menemukan tag keamanan utas untuk anggota API di referensi API. Saat menggunakannya, Anda juga perlu mempertimbangkan bagaimana panggilan API atau perubahan properti mungkin berinteraksi antara utas paralel. Biasanya aman bagi beberapa aktor untuk membaca data yang sama seperti aktor lainnya tetapi tidak mengubah status aktor lain.

Komunikasi antar-utas

Di bawah konteks multithreading, Anda masih dapat memungkinkan skrip dalam aktor yang berbeda untuk berkomunikasi satu sama lain untuk bertukar data, mengoordinasikan tugas, dan menyinkronkan kegiatan. Mesin mendukung mekanisme berikut untuk komunikasi antar-utas:

Anda dapat mendukung beberapa mekanisme untuk memenuhi kebutuhan komunikasi antar-utas Anda. Misalnya, Anda dapat mengirim tabel bersama melalui API Pesan Aktor.

Pesan aktor

API pesan aktor memungkinkan skrip, baik dalam konteks serial atau paralel, untuk mengirim data ke aktor dalam model data yang sama. Komunikasi melalui API ini bersifat asinkron, di mana pengirim tidak memblokir hingga penerima menerima pesan.

Saat mengirim pesan menggunakan API ini, Anda perlu mendefinisikan topik untuk mengkategorikan pesan. Setiap pesan hanya dapat dikirim ke satu aktor, tetapi aktor itu dapat memiliki beberapa callback yang terikat pada pesan. Hanya skrip yang merupakan keturunan dari aktor yang dapat menerima pesan.

API memiliki metode berikut:

Contoh berikut menunjukkan cara menggunakan Actor:SendMessage() untuk mendefinisikan topik dan mengirim pesan dari sisi pengirim:

Contoh Pengirim Pesan

local Workspace = game:GetService("Workspace")
-- Mengirim dua pesan ke aktor pekerja dengan topik "Salam"
local workerActor = Workspace.WorkerActor
workerActor:SendMessage("Greeting", "Halo Dunia!")
workerActor:SendMessage("Greeting", "Selamat datang")
print("Mengirim pesan")

Contoh berikut menunjukkan cara menggunakan Actor:BindToMessageParallel() untuk mengikat callback untuk topik tertentu dalam konteks paralel di sisi penerima:

Contoh Penerima Pesan

-- Mendapatkan aktor yang skrip ini adalah induknya
local actor = script:GetActor()
-- Mengikat callback untuk topik pesan "Salam"
actor:BindToMessageParallel("Greeting", function(greetingString)
print(actor.Name, "-", greetingString)
end)
print("Terikat pada pesan")

Tabel bersama

SharedTable adalah struktur data seperti tabel yang dapat diakses dari skrip yang berjalan di bawah beberapa aktor. Ini berguna untuk situasi yang melibatkan sejumlah besar data dan memerlukan state bersama antara beberapa utas. Misalnya, ketika beberapa aktor bekerja pada state dunia bersama yang tidak disimpan dalam model data.

Mengirim tabel bersama ke aktor lain tidak membuat salinan data. Sebagai gantinya, tabel bersama memungkinkan pembaruan yang aman dan atomik oleh beberapa skrip secara bersamaan. Setiap pembaruan pada tabel bersama oleh satu aktor segera terlihat oleh semua aktor. Tabel bersama juga dapat disalin dalam proses yang efisien sumber daya yang memanfaatkan pembagian struktural daripada menyalin data yang mendasarinya.

Komunikasi model data langsung

Anda juga dapat memfasilitasi komunikasi antara beberapa utas secara langsung menggunakan model data, di mana aktor yang berbeda dapat menulis dan selanjutnya membaca properti atau atribut. Namun, untuk menjaga keamanan utas, skrip yang berjalan secara paralel umumnya tidak dapat menulis ke model data. Jadi menggunakan model data langsung untuk komunikasi datang dengan pembatasan dan mungkin memaksa skrip untuk menyinkronkan secara teratur, yang dapat mempengaruhi kinerja skrip Anda.

Contoh

Validasi raycasting sisi server

Untuk pengalaman bertarung dan pertarungan, Anda perlu mengaktifkan raycasting untuk senjata pengguna Anda. Dengan klien mensimulasikan senjata untuk mencapai latensi yang baik, server harus mengkonfirmasi hit, yang melibatkan melakukan raycast dan beberapa heuristik yang mengkalkulasi kecepatan karakter yang diharapkan, dan melihat perilaku masa lalu.

Alih-alih menggunakan skrip terpusat tunggal yang terhubung ke event jarak jauh yang digunakan klien untuk berkomunikasi tentang informasi hit, Anda dapat menjalankan setiap proses validasi hit di sisi server secara paralel dengan setiap karakter pengguna memiliki event jarak jauh terpisah.

Skrip sisi server yang berjalan di bawah Actor karakter tersebut terhubung ke event jarak jauh ini menggunakan sambungan paralel untuk menjalankan logika yang relevan untuk mengkonfirmasi hit. Jika logika menemukan konfirmasi hit, kerusakan dikurangi, yang melibatkan mengubah properti, sehingga awalnya dijalankan secara serial.


local Workspace = game:GetService("Workspace")
local tool = script.Parent.Parent
local remoteEvent = Instance.new("RemoteEvent") -- Membuat event jarak jauh baru dan menempatkannya di alat
remoteEvent.Name = "RemoteMouseEvent" -- Mengubah namanya sehingga skrip lokal dapat mencarinya
remoteEvent.Parent = tool
local remoteEventConnection -- Membuat referensi untuk sambungan event jarak jauh
-- Fungsi yang mendengarkan event jarak jauh
local function onRemoteMouseEvent(player: Player, clickLocation: CFrame)
-- SERIAL: Eksekusi kode setup secara serial
local character = player.Character
-- Abaikan karakter pengguna saat melakukan raycasting
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { character }
-- PARALLEL: Melakukan raycast secara paralel
task.desynchronize()
local origin = tool.Handle.CFrame.Position
local epsilon = 0.01 -- Digunakan untuk memperpanjang sinar sedikit karena lokasi klik mungkin sedikit menyimpang dari objek
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: Kode di bawah ini mengubah status di luar aktor
task.synchronize()
explosion.DestroyJointRadiusPercent = 0 -- Membuat ledakan tidak mematikan
explosion.Position = clickLocation.Position
-- Beberapa aktor bisa mendapatkan bagian yang sama dalam raycast dan memutuskan untuk menghancurkannya
-- Ini sepenuhnya aman tetapi akan menghasilkan dua ledakan sekaligus alih-alih satu
-- Berikut ini memeriksa ganda bahwa eksekusi mencapai bagian ini terlebih dahulu
if hitPart.Parent then
explosion.Parent = Workspace
hitPart:Destroy() -- Menghancurkannya
end
end
end
end
-- Sambungkan sinyal secara serial awalnya karena beberapa kode setup tidak dapat berjalan secara paralel
remoteEventConnection = remoteEvent.OnServerEvent:Connect(onRemoteMouseEvent)

Generasi terrain prosedural sisi server

Untuk menciptakan dunia yang luas untuk pengalaman Anda, Anda dapat mengisi dunia secara dinamis. Generasi prosedural biasanya membuat potongan terrain yang independen, dengan generator melakukan kalkulasi yang relatif rumit untuk penempatan objek, penggunaan material, dan pengisian voxel. Menjalankan kode generasi secara paralel dapat meningkatkan efisiensi proses tersebut. Contoh kode berikut berfungsi sebagai contoh.


-- Eksekusi paralel membutuhkan penggunaan aktor
-- Skrip ini menggandakan dirinya sendiri; yang asli memulai proses, sedangkan yang digandakan bertindak sebagai pekerja
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
-- Tempatkan semua aktor di bawah diri sendiri
for _, actor in workers do
actor.Parent = script
end
-- Instruksikan aktor untuk menghasilkan terrain dengan mengirim pesan
-- Dalam contoh ini, aktor dipilih secara acak
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)
-- Keluar dari skrip asli; sisa kode dijalankan di setiap aktor
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
-- Mengikat callback untuk dipanggil dalam konteks eksekusi paralel
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)
-- Saat ini, WriteVoxels() harus dipanggil dalam fase serial
task.synchronize()
Workspace.Terrain:WriteVoxels(
Region3.new(corner, corner + Vector3.new(16, 16, 16)),
4,
voxels.materials,
voxels.occupancy
)
end)

Praktik terbaik

Untuk menerapkan manfaat maksimal dari pemrograman paralel, rujuk pada praktik terbaik berikut saat menambahkan kode Luau Anda:

  • Hindari Perhitungan Panjang — Bahkan dalam paralel, perhitungan panjang dapat memblokir eksekusi skrip lain dan menyebabkan lag. Hindari menggunakan pemrograman paralel untuk menangani sejumlah besar perhitungan panjang yang tidak dapat menghasilkan.

    Diagram yang menunjukkan bagaimana membebani fase eksekusi paralel masih dapat menyebabkan lag
  • Gunakan Jumlah Aktor yang Tepat — Untuk kinerja terbaik, gunakan lebih banyak Aktor. Bahkan jika perangkat memiliki lebih sedikit inti daripada Aktor, granularitas memungkinkan balancing beban yang lebih efisien di antara inti.

    Demonstrasi bagaimana menggunakan lebih banyak aktor menyeimbangkan beban di antara inti

    Ini tidak berarti Anda harus menggunakan sebanyak mungkin Aktor yang mungkin. Anda tetap harus membagi kode ke dalam Aktor berdasarkan unit logika daripada memecah kode dengan logika yang terhubung ke Aktor yang berbeda. Sebagai contoh, jika Anda ingin mengaktifkan validasi raycasting secara paralel, masuk akal untuk menggunakan 64 Aktor atau lebih daripada hanya 4, bahkan jika Anda menargetkan sistem 4-inti. Ini berharga untuk skalabilitas sistem dan memungkinkan untuk mendistribusikan pekerjaan berdasarkan kemampuan perangkat keras yang mendasarinya. Namun, Anda juga sebaiknya tidak menggunakan terlalu banyak Aktor, yang sulit untuk dikelola.

©2026 Roblox Corporation. Roblox, logo Roblox, dan Powering Imagination termasuk dalam merek dagang kami yang terdaftar dan tidak terdaftar di AS dan negara lainnya.