ด้วยโมเดลการเขียนโปรแกรม Parallelu Luau คุณสามารถรันโค้ดบนหลายเธรดพร้อมกัน ซึ่งสามารถปรับปรุงประสิทธิภาพของประสบการณ์ของคุณได้ เมื่อคุณขยายประสบการณ์ของคุณด้วยเนื้อหามากขึ้น คุณสามารถนำโมเดลนี้มาใช้เพื่อช่วยรักษาประสิทธิภาพและความปลอดภัยของสคริปต์ Luau ของคุณ
โมเดลการเขียนโปรแกรมขนาน
โดยค่าเริ่มต้น สคริปต์จะถูกประมวลผลตามลำดับ หากประสบการณ์ของคุณมีตรรกะหรือเนื้อหาที่ซับซ้อน เช่น ตัวละครที่ไม่ใช่ผู้เล่น (NPCs), การตรวจสอบความถูกต้องของเรย์แคสติ้ง และการสร้างแบบอัตโนมัติ การประมวลผลตามลำดับอาจทำให้เกิดความล่าช้าสำหรับผู้ใช้ของคุณ ด้วยโมเดลการเขียนโปรแกรมขนาน คุณสามารถ แบ่งงานออกเป็นสคริปต์หลาย ๆ ตัว และรันพร้อมกันได้ ซึ่งทำให้โค้ดของคุณรันได้เร็วขึ้น ซึ่งช่วยปรับปรุงประสบการณ์ของผู้ใช้
โมเดลการเขียนโปรแกรมขนานยังเพิ่มข้อดีด้านความปลอดภัยให้กับโค้ดของคุณ โดยการแบ่งโค้ดออกเป็นหลายเธรด เมื่อคุณแก้ไขโค้ดในเธรดหนึ่ง มันจะไม่กระทบต่อโค้ดอื่น ๆ ที่หมุนอยู่ในขนาน สิ่งนี้ช่วยลดความเสี่ยงในการมีบั๊กหนึ่งในโค้ดของคุณทำให้ประสบการณ์ทั้งหมดเสียหาย และลดเวลาล่าช้าสำหรับผู้ใช้ในเซิร์ฟเวอร์สดเมื่อคุณกดอัปเดต
การนำโมเดลการเขียนโปรแกรมแบบขนานมาประยุกต์ใช้ไม่ได้หมายความว่าคุณต้องใส่ทุกอย่างลงในหลายเธรด ตัวอย่างเช่น การตรวจสอบความถูกต้องของเรย์แคสติ้ง ฝั่งเซิร์ฟเวอร์ จะตั้งค่าผู้ใช้แต่ละคนเป็นเหตุการณ์ระยะไกลในขนาน แต่ยังคงต้องการให้โค้ดเริ่มต้นทำงานเรียงโดยเพื่อเปลี่ยนแปลงคุณสมบัติทั่วโลก ซึ่งเป็นรูปแบบที่พบได้ทั่วไปในการประมวลผลแบบขนาน
ส่วนใหญ่คุณต้องรวมระยะเวลาการประมวลผลแบบเรียงและแบบขนานเพื่อนำไปสู่ผลลัพธ์ที่ต้องการ เนื่องจากปัจจุบันมีบางการดำเนินการที่ไม่รองรับการทำงานขนานซึ่งอาจทำให้สคริปต์ไม่สามารถทำงานได้ เช่น การแก้ไขอินสแตนซ์ในระยะเวลาขนาน สำหรับข้อมูลเพิ่มเติมเกี่ยวกับระดับการใช้งานของ API ในโหมดขนาน ดูที่ ความปลอดภัยของเธรด.
แบ่งโค้ดออกเป็นหลายเธรด
หากต้องการรันสคริปต์ของประสบการณ์ของคุณในหลายเธรดพร้อมกัน คุณต้องแบ่งเป็นชิ้นส่วนที่มีเหตุผลภายใต้ นักแสดง ต่าง ๆ ใน โมเดลข้อมูล นักแสดงจะแสดงโดยอินสแตนซ์ Actor ที่สืบทอดมาจาก DataModel พวกเขาทำหน้าที่เป็นหน่วยของการแยกการประมวลผลที่แจกจ่ายภาระไปยังหลายคอร์ที่ทำงานในเวลาเดียวกัน
วางอินสแตนซ์นักแสดง
คุณสามารถวางนักแสดงในภาชนะที่เหมาะสมหรือใช้พวกเขาเพื่อแทนที่ประเภทอินสแตนซ์ระดับบนสุดของเอนทิตี 3D ของคุณ เช่น NPCs และเรย์แคสเตอร์ จากนั้นเพิ่มสคริปต์ที่สอดคล้องกัน

ในสถานการณ์ส่วนใหญ่ คุณไม่ควรวางนักแสดงเป็นบุตรของนักแสดงตัวอื่นในโมเดลข้อมูล อย่างไรก็ตาม หากคุณตัดสินใจที่จะวางสคริปต์ซึ่งซ้อนอยู่ภายในนักแสดงหลายตัวตามกรณีการใช้งานเฉพาะของคุณ สคริปต์จะถูกเป็นเจ้าของโดยนักแสดงบรรพบุรุษที่ใกล้ที่สุด

ปรับเวลาเธรด
แม้ว่าการวางสคริปต์ภายใต้นักแสดงจะทำให้พวกเขามีความสามารถในการประมวลผลขนาน แต่ด้วยค่าเริ่มต้น โค้ดยังคงทำงานบนเธรดเดียวเรียงตามลำดับ ซึ่งไม่ช่วยปรับปรุงประสิทธิภาพการทำงานของรันไทม์ คุณต้องเรียกใช้ task.desynchronize() ซึ่งเป็นฟังก์ชันที่สามารถหยุดชะงักได้ที่ระงับการดำเนินการของโครูทีนปัจจุบันเพื่อเรียกใช้โค้ดในรูปแบบขนานและกลับมาทำงานต่อในโอกาสการทำงานในรูปแบบขนานครั้งถัดไป เพื่อเปลี่ยนสคริปต์กลับไปยังการประมวลผลแบบเรียงลำดับ ให้เรียกใช้ task.synchronize().
ซึ่งคุณสามารถใช้ RBXScriptSignal:ConnectParallel() เมื่อต้องการกำหนดเวลาสัญญาณเพื่อเรียกใช้โค้ดของคุณในรูปแบบขนานทันทีเมื่อมีการทริกเกอร์ คุณไม่จำเป็นต้องเรียกใช้ task.desynchronize() ข้างในสัญญาณ Callback.
ปรับเวลาเธรด
local RunService = game:GetService("RunService")
RunService.Heartbeat:ConnectParallel(function()
... -- โค้ดพร้อมขนานซึ่งคำนวณการอัปเดตสถานะ
task.synchronize()
... -- โค้ดเรียงที่เปลี่ยนแปลงสถานะของอินสแตนซ์
end)
สคริปต์ที่เป็นส่วนหนึ่งของนักแสดงเดียวกันจะทำงานเรียงตามลำดับเมื่อเปรียบเทียบกัน ดังนั้นคุณต้องมีนักแสดงหลายคน ตัวอย่างเช่น หากคุณใส่สคริปต์ที่เปิดใช้งานขนานทั้งหมดสำหรับ NPC ของคุณในนักแสดงตัวเดียว พวกเขายังคงทำงานเรียงตามลำดับในเธรดเดียว แต่ถ้าคุณมีนักแสดงหลายตัวสำหรับตรรกะ NPC ที่แตกต่างกัน แต่ละตัวจะทำงานในขนานในเธรดของตนเอง สำหรับข้อมูลเพิ่มเติม ดูที่ แนวทางปฏิบัติที่ดีที่สุด.


ความปลอดภัยของเธรด
ระหว่างการประมวลผลขนาน คุณสามารถเข้าถึงอินสแตนซ์ส่วนใหญ่ของลำดับ DataModel ตามปกติ แต่คุณสมบัติและฟังก์ชันบางอย่างของ API ไม่ปลอดภัยในการอ่านหรือเขียน หากคุณใช้พวกเขาในโค้ดขนานของคุณ เอนจิ้น Roblox สามารถตรวจจับและป้องกันการเข้าถึงเหล่านี้ได้โดยอัตโนมัติ
สมาชิก API มีระดับความปลอดภัยของเธรดที่บ่งบอกว่าคุณสามารถใช้พวกเขาในโค้ดขนานของคุณได้หรือไม่และอย่างไร ตามตารางต่อไปนี้:
| ระดับความปลอดภัย | สำหรับคุณสมบัติ | สำหรับฟังก์ชัน |
|---|---|---|
| ไม่ปลอดภัย | ไม่สามารถอ่านหรือเขียนในขนานได้ | ไม่สามารถเรียกใช้ในขนานได้ |
| อ่านขนาน | สามารถอ่านได้แต่ไม่สามารถเขียนในขนานได้ | N/A |
| ปลอดภัยในท้องถิ่น | สามารถใช้ภายในนักแสดงเดียวกัน; สามารถอ่านได้แต่ไม่สามารถเขียนโดย Actors อื่น ๆ ในลักษณะขนานได้ | สามารถเรียกใช้ภายในนักแสดงเดียวกัน; ไม่สามารถเรียกใช้โดย Actors อื่น ๆ ในลักษณะขนานได้ |
| ปลอดภัย | สามารถอ่านและเขียนได้ | สามารถเรียกใช้ได้ |
คุณสามารถหาตราสัญลักษณ์ความปลอดภัยของเธรดสำหรับสมาชิก API ได้ใน API reference เมื่อใช้งานพวกเขาคุณยังควรพิจารณาว่าการเรียก API หรือการเปลี่ยนแปลงสถานะอาจมีปฏิสัมพันธ์ระหว่างเธรดขนาน โดยทั่วไปมันปลอดภัยสำหรับนักแสดงหลายตัวที่จะอ่านข้อมูลเดียวกันจากนักแสดงอื่น แต่ไม่เปลี่ยนแปลงสถานะของนักแสดงอื่น
การสื่อสารข้ามเธรด
ในบริบทหลายเธรด คุณยังสามารถอนุญาตให้สคริปต์ในนักแสดงที่แตกต่างกันสื่อสารกันเพื่อแลกเปลี่ยนข้อมูล ประสานงานงาน และซิงโครไนซ์กิจกรรม เอนจินสนับสนุนกลไกต่อไปนี้สำหรับการสื่อสารข้ามเธรด:
- การส่งข้อความนักแสดง API สำหรับการส่งข้อความไปยังนักแสดง โดยใช้สคริปต์
- ตารางที่ใช้ร่วมกัน โครงสร้างข้อมูลสำหรับการแบ่งปันข้อมูลจำนวนมากระหว่างนักแสดงหลายตัวในสถานะที่ใช้ร่วมกันอย่างมีประสิทธิภาพ
- การสื่อสารโดยตรงในโมเดลข้อมูล สำหรับการสื่อสารง่าย ๆ ด้วยเงื่อนไข
คุณสามารถสนับสนุนกลไกหลายสัญญาณเพื่อรองรับความต้องการในการสื่อสารข้ามเธรดของคุณ ตัวอย่างเช่น คุณสามารถส่งตารางที่ใช้ร่วมกันผ่าน API การส่งข้อความนักแสดง
การส่งข้อความนักแสดง
API การส่งข้อความนักแสดง อนุญาตให้สคริปต์ ไม่ว่าจะในบริบทเรียงลำดับหรือขนาน ส่งข้อมูลไปยังนักแสดงในโมเดลข้อมูลเดียวกัน การสื่อสารผ่าน API นี้เป็นแบบอะซิงโครนัส ซึ่งผู้ส่งจะไม่บล็อกจนกว่าผู้รับจะได้รับข้อความ
เมื่อส่งข้อความโดยใช้ API นี้ คุณต้องกำหนด หัวข้อ สำหรับการจำแนกประเภทข้อความ แต่ละข้อความสามารถส่งไปยังนักแสดงตัวเดียว แต่ที่นักแสดงนั้นสามารถมีการประชุมหลายรายการที่ผูกกับข้อความได้เท่านั้น สคริปต์ที่เป็นทายาทของนักแสดงเท่านั้นที่สามารถรับข้อความได้
API มีวิธีการดังต่อไปนี้:
- Actor:SendMessage() สำหรับการส่งข้อความไปยังนักแสดง
- Actor:BindToMessage() สำหรับการผูกคอลแบ็ก Luau เข้ากับข้อความที่มีหัวข้อที่กำหนดในบริบทเรียงลำดับ
- Actor:BindToMessageParallel() สำหรับการผูกคอลแบ็ก Luau เข้ากับข้อความที่มีหัวข้อที่กำหนดในบริบทขนาน
ตัวอย่างต่อไปนี้แสดงถึงวิธีการใช้ Actor:SendMessage() เพื่อตั้งค่าหัวข้อและส่งข้อความจากฝั่งผู้ส่ง:
ตัวอย่างผู้ส่งข้อความlocal Workspace = game:GetService("Workspace")-- ส่งข้อความสองข้อความไปยังนักแสดงที่ทำงานด้วยหัวข้อ "Greeting"local workerActor = Workspace.WorkerActorworkerActor:SendMessage("Greeting", "Hello World!")workerActor:SendMessage("Greeting", "Welcome")print("ส่งข้อความแล้ว")
ตัวอย่างต่อไปนี้แสดงถึงวิธีการใช้ Actor:BindToMessageParallel() เพื่อผูกคอลแบ็กสำหรับหัวข้อเฉพาะในบริบทขนานจากฝั่งผู้รับ:
ตัวอย่างผู้รับข้อความ
-- รับนักแสดงที่สคริปต์นี้อยู่ภายใต้
local actor = script:GetActor()
-- ผูกคอลแบ็กสำหรับหัวข้อข้อความ "Greeting"
actor:BindToMessageParallel("Greeting", function(greetingString)
print(actor.Name, "-", greetingString)
end)
print("ผูกข้อความแล้ว")
ตารางที่ใช้ร่วมกัน
SharedTable เป็นโครงสร้างข้อมูลคล้ายตารางที่เข้าถึงได้จากสคริปต์ที่รันภายใต้หลายนักแสดง มันมีความสำคัญในสถานการณ์ที่มีข้อมูลจำนวนมากและต้องการสถานะที่ใช้ร่วมกันระหว่างเธรดหลายตัว สำหรับตัวอย่าง เมื่อมีนักแสดงหลายตัวทำงานในสถานะโลกทั่วไปที่ไม่ได้เก็บอยู่ในโมเดลข้อมูล
การส่งตารางที่ใช้ร่วมกันไปยังนักแสดงอื่นจะไม่สร้างสำเนาของข้อมูล แทนที่ตารางที่ใช้ร่วมกันช่วยให้มีการอัปเดตที่ปลอดภัยและเป็นอะตอมโดยสคริปต์หลายตัวในเวลาเดียวกัน ทุกการอัปเดตที่ทำโดยนักแสดงตัวหนึ่งในตารางที่ใช้ร่วมกันจะปรากฏให้เห็นทันทีต่อทุกนักแสดง ตารางที่ใช้ร่วมกันยังสามารถถูกโคลนในกระบวนการที่มีประสิทธิภาพในทรัพยากรที่ใช้การแบ่งปันโครงสร้างแทนการคัดลอกข้อมูลพื้นฐาน
การสื่อสารโดยตรงในโมเดลข้อมูล
คุณยังสามารถอำนวยความสะดวกในการสื่อสารระหว่างหลายเธรดโดยตรงโดยใช้โมเดลข้อมูลซึ่งนักแสดงที่แตกต่างกันสามารถเขียนและอ่านคุณสมบัติหรือแอตทริบิวต์ได้ในภายหลัง อย่างไรก็ตามเพื่อรักษาความปลอดภัยของเธรด สคริปต์ที่ทำงานในส่วนขนานจะไม่สามารถเขียนไปยังโมเดลข้อมูลได้ ดังนั้น การใช้งานโมเดลข้อมูลโดยตรงเพื่อการสื่อสารจึงมีข้อจำกัดและอาจบังคับให้สคริปต์ทำการซิงโครไนซ์บ่อยซึ่งอาจส่งผลต่อประสิทธิภาพของสคริปต์ของคุณ
ตัวอย่าง
การตรวจสอบความถูกต้องของเรย์แคสติ้งฝั่งเซิร์ฟเวอร์
สำหรับการต่อสู้และประสบการณ์การต่อสู้ คุณจำเป็นต้องเปิดใช้งาน เรย์แคสติ้ง สำหรับอาวุธของผู้ใช้ ด้วยลูกค้าจำลองอาวุธเพื่อให้ได้ความล่าช้าที่ดี เซิร์ฟเวอร์จะต้องยืนยันการโจมตีซึ่งเกี่ยวข้องกับการทำเรย์แคสและการคำนวณเชิงพฤติกรรมที่คำนวณความเร็วที่คาดการณ์ของตัวละคร และดูพฤติกรรมในอดีต
แทนที่จะใช้สคริปต์ศูนย์รวมภายในที่เชื่อมต่อกับเหตุการณ์ระยะไกลที่คลient ใช้ในการสื่อสารข้อมูลการโจมตี คุณสามารถทำการตรวจสอบการโจมตีแต่ละครั้งในด้านเซิร์ฟเวอร์ได้ในขนานโดยทุกตัวละครของผู้ใช้มีเหตุการณ์ระยะไกลที่แยกต่างหาก
สคริปต์ด้านเซิร์ฟเวอร์ที่ทำงานภายใต้ Actor ของตัวละครนั้นเชื่อมต่อกับเหตุการณ์ระยะไกลนี้โดยใช้การเชื่อมต่อขนานเพื่อรันตรรกะที่เกี่ยวข้องเพื่อยืนยันการโจมตี หากตรรกะพบนการยืนยันการโจมตี ความเสียหายจะถูกหักซึ่งเกี่ยวข้องกับการเปลี่ยนแปลงคุณสมบัติ ดังนั้นมันจึงทำงานเรียงตามลำดับในตอนแรก
local Workspace = game:GetService("Workspace")
local tool = script.Parent.Parent
local remoteEvent = Instance.new("RemoteEvent") -- สร้างเหตุการณ์ระยะไกลใหม่และบริบทให้กับเครื่องมือ
remoteEvent.Name = "RemoteMouseEvent" -- เปลี่ยนชื่อเพื่อให้สคริปต์ท้องถิ่นสามารถมองหา
remoteEvent.Parent = tool
local remoteEventConnection -- สร้างการอ้างอิงสำหรับการเชื่อมต่อของเหตุการณ์ระยะไกล
-- ฟังก์ชันที่ฟังเหตุการณ์ระยะไกล
local function onRemoteMouseEvent(player: Player, clickLocation: CFrame)
-- SERIAL: รันโค้ดตั้งค่าในลำดับ
local character = player.Character
-- เพิกเฉยต่อตัวละครของผู้ใช้ขณะทำเรย์แคสติ้ง
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { character }
-- PARALLEL: ทำการเรย์แคสในขนาน
task.desynchronize()
local origin = tool.Handle.CFrame.Position
local epsilon = 0.01 -- ใช้เพื่อขยายเรย์ออกไปเล็กน้อยเนื่องจากสถานที่คลิกอาจมีการเปลี่ยนแปลงเล็กน้อยจากวัตถุ
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: โค้ดด้านล่างเปลี่ยนแปลงสถานะนอกนักแสดง
task.synchronize()
explosion.DestroyJointRadiusPercent = 0 -- ทำให้การระเบิดไม่มีอันตราย
explosion.Position = clickLocation.Position
-- นักแสดงหลายคนอาจได้รับส่วนเดียวกันในเรย์แคสและตัดสินใจทำลายมัน
-- นี้ปลอดภัยอย่างสมบูรณ์ แต่จะทำให้การระเบิดสองครั้งเกิดขึ้นในครั้งเดียวแทนที่เป็นหนึ่ง
-- ต่อไปนี้เป็นการตรวจสอบขั้นสุดท้ายว่าการดำเนินการมายังจุดนี้ก่อน
if hitPart.Parent then
explosion.Parent = Workspace
hitPart:Destroy() -- ทำลายมัน
end
end
end
end
-- เชื่อมต่อสัญญาณในลำดับในตอนแรกเนื่องจากโค้ดบางตัวไม่สามารถทำงานในขนาน
remoteEventConnection = remoteEvent.OnServerEvent:Connect(onRemoteMouseEvent)
การสร้างภูมิประเทศเชิงพรรณนาฝั่งเซิร์ฟเวอร์
เพื่อสร้างโลกกว้างสำหรับประสบการณ์ของคุณ คุณสามารถทำให้โลกเต็มไปด้วยข้อมูลแบบพลศาสตร์ การสร้างเชิงพรรณนามักสร้างชิ้นส่วนภูมิประเทศที่เป็นอิสระ โดยที่ผู้สร้างทำการคำนวณซับซ้อนสำหรับการวางวัตถุ การใช้วัสดุ และการเติม voxel การรันโค้ดการสร้างในขนานสามารถเพิ่มประสิทธิภาพของกระบวนการได้ ตัวอย่างโค้ดต่อไปนี้แสดงถึงตัวอย่าง
-- การประมวลผลขนานต้องการการใช้ดาราราศี
-- สคริปต์นี้โคลนตัวเอง; ตัวดั้งเดิมเริ่มกระบวนการ ในขณะที่โคลนทำหน้าที่เป็นผู้ทำงาน
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
-- วางงานทุกนักแสดงภายใต้ตนเอง
for _, actor in workers do
actor.Parent = script
end
-- สั่งให้นักแสดงสร้างภูมิประเทศโดยการส่งข้อความ
-- ในตัวอย่างนี้ นักแสดงได้รับเลือกแบบสุ่ม
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)
-- ออกจากสคริปต์เดิม; โค้ดที่เหลือทำงานในนักแสดงแต่ละตัว
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
-- ผูกคอลแบ็กให้ถูกเรียกในบริบทการประมวลผลขนาน
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)
-- ขณะนี้ WriteVoxels() ต้องถูกเรียกในระยะเวลาที่เรียง
task.synchronize()
Workspace.Terrain:WriteVoxels(
Region3.new(corner, corner + Vector3.new(16, 16, 16)),
4,
voxels.materials,
voxels.occupancy
)
end)
แนวทางปฏิบัติที่ดีที่สุด
เพื่อให้ได้ประโยชน์สูงสุดจากการโปรแกรมแบบขนาน โปรดทำตามแนวทางปฏิบัติดังต่อไปนี้เมื่อเพิ่มโค้ด Luau ของคุณ:
หลีกเลี่ยงการคำนวณนาน — แม้ว่าจะขนานอยู่ การคำนวณยาว ๆ สามารถบล็อกการประมวลผลของสคริปต์อื่น ๆ และทำให้เกิดความล่าช้า หลีกเลี่ยงการใช้การเขียนโปรแกรมแบบขนานเพื่อจัดการกับการคำนวณที่ยาวและไม่มีการหยุดชะงักเป็นจำนวนมาก

ใช้จำนวน นักแสดงที่เหมาะสม — สำหรับประสิทธิภาพที่ดีที่สุด ใช้ Actors มากขึ้น แม้ว่าอุปกรณ์จะมีคอร์น้อยกว่านักแสดง แต่การแบ่งละเอียดยังช่วยให้มีการ กระจายภาระที่มีประสิทธิภาพระหว่างคอร์

นี่ไม่ได้หมายความว่าคุณควรใช้ Actors ให้มากที่สุด คุณยังควรแบ่งโค้ดออกเป็น Actors ตามหน่วยตรรกะ แทนที่จะย้ายโค้ดที่เชื่อมต่อกันไปยัง Actors ที่แตกต่างกัน ตัวอย่างเช่น หากคุณต้องการเปิดใช้งาน การตรวจสอบความถูกต้องของเรย์แคสติ้ง ในขนาน เป็นเรื่องสมเหตุสมผลที่จะใช้ 64 Actors และมากกว่าแค่ 4 ตัว แม้ว่าคุณจะกำหนดเป้าหมายที่ระบบ 4-core นี่เป็นผลดีต่อการปรับขนาดของระบบและช่วยให้อำนวยงานกระจายตามความสามารถของฮาร์ดแวร์ที่อยู่เบื้องหลัง แต่คุณก็ไม่ควรใช้ Actors มากเกินไปจนยากต่อการบำรุงรักษา