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 permainan Anda. Saat Anda memperluas permainan Anda dengan lebih banyak konten, Anda dapat mengadopsi model ini untuk membantu menjaga kinerja dan keamanan skrip Luau Anda.

Model pemrograman paralel

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

Model pemrograman paralel juga menambahkan manfaat keamanan pada kode Anda. Dengan membagi 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 permainan, dan meminimalkan penundaan bagi pengguna di server langsung ketika Anda mendorong pembaruan.

Mengadopsi model pemrograman paralel tidak berarti menempatkan semuanya di beberapa utas. Misalnya, validasi raycasting sisi server menetapkan setiap pengguna individu sebuah acara jarak jauh secara paralel tetapi masih memerlukan kode awal untuk dijalankan secara serial untuk mengubah properti global, yang merupakan pola umum untuk eksekusi paralel.

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

Membagi kode menjadi beberapa utas

Untuk menjalankan skrip permainan Anda di beberapa utas secara bersamaan, Anda perlu membaginya menjadi potongan logis di bawah aktor yang berbeda dalam model data. Aktor diwakili oleh instance Actor yang mewarisi dari DataModel. Mereka berfungsi sebagai unit isolasi eksekusi yang mendistribusikan beban di antara beberapa inti yang berjalan secara bersamaan.

Tempatkan instance aktor

Anda dapat menempatkan aktor di wadah yang tepat atau menggunakannya untuk menggantikan jenis instance tingkat atas dari entitas 3D Anda seperti NPC dan raycaster, kemudian tambahkan skrip yang sesuai.

Contoh Skrip di bawah Aktor

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

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 di satu utas secara serial, 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 serial, 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 instance
end)

Skrip yang merupakan bagian dari aktor yang sama selalu dieksekusi secara berurutan satu sama lain, jadi Anda memerlukan beberapa aktor. Misalnya, jika Anda menempatkan semua skrip perilaku yang diaktifkan paralel untuk NPC Anda dalam satu aktor, mereka tetap berjalan secara serial di 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 di satu utas
Kode paralel dalam Aktor yang berjalan secara bersamaan di beberapa utas

Keamanan utas

Selama eksekusi paralel, Anda dapat mengakses sebagian besar instance 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 dalam tabel berikut:

Tingkat keamananUntuk propertiUntuk fungsi
Tidak AmanTidak dapat dibaca atau ditulis secara paralel.Tidak dapat dipanggil secara paralel.
Baca ParalelDapat dibaca tetapi tidak dapat ditulis secara paralel.N/A
Aman LokalDapat digunakan dalam Aktor yang sama; dapat dibaca tetapi tidak dapat ditulis oleh Actors lain secara paralel.Dapat dipanggil dalam Aktor yang sama; tidak dapat dipanggil oleh Actors 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 harus mempertimbangkan bagaimana panggilan API atau perubahan properti mungkin berinteraksi antara utas paralel. Biasanya aman bagi beberapa aktor untuk membaca data yang sama seperti aktor lain tetapi tidak memodifikasi status aktor lain.

Komunikasi antar-utas

Dalam konteks multithreading, Anda masih dapat memungkinkan skrip di aktor yang berbeda untuk berkomunikasi satu sama lain untuk bertukar data, mengoordinasikan tugas, dan menyinkronkan aktivitas. 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 tersebut 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 di sisi pengirim:

Contoh Pengirim Pesan
local Workspace = game:GetService("Workspace")
-- Kirim dua pesan ke aktor pekerja dengan topik "Salam"
local workerActor = Workspace.WorkerActor
workerActor:SendMessage("Greeting", "Halo Dunia!")
workerActor:SendMessage("Greeting", "Selamat Datang")
print("Pesan terkirim")

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

Contoh Penerima Pesan
-- Dapatkan aktor yang skrip ini dimiliki
local actor = script:GetActor()
-- Ikat 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 mirip tabel yang dapat diakses dari skrip yang berjalan di bawah beberapa aktor. Ini berguna untuk situasi yang melibatkan sejumlah besar data dan memerlukan status bersama yang umum antara beberapa utas. Misalnya, ketika beberapa aktor bekerja pada status dunia bersama yang tidak disimpan dalam model data.

Mengirim tabel bersama ke aktor lain tidak membuat salinan data. Sebaliknya, 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 dikloning dalam proses yang efisien sumber daya yang memanfaatkan berbagi struktural alih-alih 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 kemudian 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 secara langsung untuk komunikasi datang dengan batasan dan dapat memaksa skrip untuk menyinkronkan secara sering, yang dapat mempengaruhi kinerja skrip Anda.

Contoh

Validasi raycasting sisi server

Untuk permainan pertarungan dan pertempuran, Anda perlu mengaktifkan raycasting untuk senjata pengguna Anda. Dengan klien mensimulasikan senjata untuk mencapai latensi yang baik, server harus mengonfirmasi hit, yang melibatkan melakukan raycast dan sejumlah heuristik yang menghitung kecepatan karakter yang diharapkan, dan melihat perilaku masa lalu.

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

Skrip sisi server yang berjalan di bawah Actor karakter tersebut terhubung ke acara jarak jauh ini menggunakan koneksi paralel untuk menjalankan logika yang relevan untuk mengonfirmasi 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") -- Buat acara jarak jauh baru dan tempatkan di alat
remoteEvent.Name = "RemoteMouseEvent" -- Ganti namanya agar skrip lokal dapat mencarinya
remoteEvent.Parent = tool
local remoteEventConnection -- Buat referensi untuk koneksi acara jarak jauh
-- Fungsi yang mendengarkan acara 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: Lakukan 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 -- Buat 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
-- Pemeriksaan ganda berikut memastikan bahwa eksekusi sampai ke bagian ini terlebih dahulu
if hitPart.Parent then
explosion.Parent = Workspace
hitPart:Destroy() -- Hancurkan itu
end
end
end
end
-- Hubungkan sinyal secara serial terlebih dahulu karena beberapa kode setup tidak dapat dijalankan secara paralel
remoteEventConnection = remoteEvent.OnServerEvent:Connect(onRemoteMouseEvent)

Generasi terrain prosedural sisi server

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

-- Eksekusi paralel memerlukan penggunaan aktor
-- Skrip ini mengkloning dirinya sendiri; yang asli memulai proses, sementara klon 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 berjalan 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
-- Ikat 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 maksimum 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 volume besar perhitungan panjang yang tidak dapat ditunda.

    Diagram yang menunjukkan bagaimana membebani fase eksekusi paralel dapat menyebabkan lag
  • Gunakan Jumlah Aktor yang Tepat — Untuk kinerja terbaik, gunakan lebih banyak Actors. Bahkan jika perangkat memiliki lebih sedikit inti daripada Actors, granularitas memungkinkan penyeimbangan 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 Actors. Anda tetap harus membagi kode menjadi Actors berdasarkan unit logika daripada memecah kode dengan logika yang terhubung ke Actors yang berbeda. Misalnya, jika Anda ingin mengaktifkan validasi raycasting secara paralel, masuk akal untuk menggunakan 64 Actors dan lebih banyak lagi 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 tidak boleh menggunakan terlalu banyak Actors, yang sulit untuk dipelihara.

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