Güncelleme: 2018'de Unity, işi boşaltmanın ve çoklu CPU çekirdeğini kullanmanın bir yolu olarak bir C # İş Sistemini piyasaya sürüyor.
Aşağıdaki cevap bu sistemden önce gelir. Yine de işe yarayacak, ancak ihtiyaçlarınıza bağlı olarak modern Birlik'te daha iyi seçenekler mevcut olabilir. Özellikle, iş sistemi, aşağıda açıklanan, elle oluşturulan iş parçacıklarının güvenli bir şekilde erişebileceği konusundaki bazı kısıtlamaları gideriyor gibi görünmektedir. Örneğin, radikalleri gösteren ve paralel olarak kafesler oluşturan önizleme raporunu deneyen geliştiriciler .
Kullanıcıları bu iş sistemini kullanarak deneyim sahibi olanları, motorun mevcut durumunu yansıtan kendi cevaplarını eklemek için davet ediyorum.
Birlik'teki ağır görevler için iş parçacığını geçmişte kullandım (genellikle görüntü ve geometri işleme) ve iki uyarı ile diğer C # uygulamalarında iş parçacığı kullanmaktan çok farklı değil:
Unity, biraz daha eski bir .NET alt kümesi kullandığından, kutudan kullanamayacağımız bazı yeni iş parçacığı özellikleri ve kitaplıkları vardır, ancak hepsi orada.
Almo'nun yukarıdaki bir açıklamada not ettiği gibi, çoğu Unity türü güvenli değildir ve bunları ana ipten oluşturmaya, kullanmaya ve hatta karşılaştırmaya çalışırsanız istisnalar atar. Akılda tutulması gereken şeyler:
Yaygın bir durum, üyelerine erişmeye çalışmadan önce bir GameObject veya Monobehaviour referansının boş olup olmadığını kontrol etmektir. myUnityObject == null
UnityEngine.Object öğesinden çıkan herhangi bir şey için aşırı yüklenmiş bir işleci çağırır, ancak System.Object.ReferenceEquals()
bunun etrafında bir dereceye kadar çalışır - yalnızca bir Destroy () ed GameObject öğesinin aşırı yüklemeyi null değerine eşit olarak karşılaştırdığını, ancak henüz null için ReferenceEqual olmadığını unutmayın.
Unity türlerinden parametreleri okumak genellikle başka bir iş parçacığında güvenlidir (yukarıdaki gibi boşları kontrol etmeye dikkat ettiğiniz sürece hemen bir istisna atmayacaktır), ancak Philipp'in burada ana iş parçacığının durumu değiştirdiği uyarısını not edin. sen okurken. Tutarsız durumları okumaktan kaçınmak için kimin neyi ne zaman değiştirebileceği konusunda disiplinli olmanız gerekir; bu durum, izleyebileceğimiz yirmi altı milisaniyelik sürelere bağlı olduklarından, izini sürdürebilmeleri zor olan hatalara yol açabilir. İsteğe bağlı olarak üremiyorum.
Rastgele ve Zaman statik üyeleri kullanılamaz. Rastgele olmanız gerekiyorsa, iş parçacığı başına bir System.Random örneği ve zamanlama bilgisine ihtiyacınız varsa System.Diagnostics.Stopwatch'ı oluşturun.
Mathf fonksiyonları, Vector, Matrix, Quaternion ve Color yapılarının tümü iş parçacığı boyunca iyi çalışır, böylece hesaplamalarınızın çoğunu ayrı ayrı yapabilirsiniz
GameObjects oluşturma, Monobehaviours ekleme veya Doku, Kafes, Malzeme vb. Oluşturma / güncelleme işlemlerinin hepsi ana iş parçacığında gerçekleşmelidir. Geçmişte bunlarla çalışmam gerektiğinde, işçi-iş parçacığımın ham verileri hazırladığı bir üretici-tüketici kuyruğu hazırladım (bir örgü veya dokuya uygulanacak büyük bir vektör / renk dizisi gibi), ve ana iş parçacığındaki bir Güncelleme veya Koroutin veriler için anket yapar ve uygular.
Bu notların dışında kalıyorum, işte genelde dişli işlerde kullandığım bir kalıp. Bunun en iyi uygulama şekli olduğunu garanti etmiyorum ama işi halleder. (Geliştirilmesi gereken yorumlar veya düzenlemeler memnuniyetle karşılanmaktadır - iş parçacığının yalnızca temelleri bildiğim çok derin bir konu olduğunu biliyorum)
using UnityEngine;
using System.Threading;
public class MyThreadedBehaviour : MonoBehaviour
{
bool _threadRunning;
Thread _thread;
void Start()
{
// Begin our heavy work on a new thread.
_thread = new Thread(ThreadedWork);
_thread.Start();
}
void ThreadedWork()
{
_threadRunning = true;
bool workDone = false;
// This pattern lets us interrupt the work at a safe point if neeeded.
while(_threadRunning && !workDone)
{
// Do Work...
}
_threadRunning = false;
}
void OnDisable()
{
// If the thread is still running, we should shut it down,
// otherwise it can prevent the game from exiting correctly.
if(_threadRunning)
{
// This forces the while loop in the ThreadedWork function to abort.
_threadRunning = false;
// This waits until the thread exits,
// ensuring any cleanup we do after this is safe.
_thread.Join();
}
// Thread is guaranteed no longer running. Do other cleanup tasks.
}
}
Çalışmayı kesinlikle hız için dişler arasında bölmeniz gerekmiyorsa ve bunu engellememenin bir yolunu arıyorsanız, oyununuzun geri kalanı tıklamaya devam ediyor, Unity'deki daha hafif bir çözüm Coroutines . Bunlar, bazı işleri yapabilen işlevlerdir ve daha sonra ne yaptığını devam ettirmek ve daha sonra kesintisiz bir şekilde devam etmek için motora tekrar kontrol sağlar.
using UnityEngine;
using System.Collections;
public class MyYieldingBehaviour : MonoBehaviour
{
void Start()
{
// Begin our heavy work in a coroutine.
StartCoroutine(YieldingWork());
}
IEnumerator YieldingWork()
{
bool workDone = false;
while(!workDone)
{
// Let the engine run for a frame.
yield return null;
// Do Work...
}
}
}
Bu, herhangi bir özel temizlik hususuna ihtiyaç duymaz, çünkü motor (söyleyebileceğim kadarıyla), sizin için tahrip olmuş nesnelerden gelen korotenlerden kurtulur.
Yöntemin tüm yerel durumu, üretilip devam ettiğinde korunur; bu nedenle, birçok amaç, başka bir iş parçacığında kesintisiz çalışıyormuş gibi çalışır (ancak ana iş parçacığında çalışmanın tüm kolaylıklarına sahipsiniz). Her yinelemenin, ana ipliğinizi makul olmayan bir şekilde yavaşlatmayacak kadar kısa olduğundan emin olmanız gerekir.
Önemli işlemlerin bir verimle ayrılmadığından emin olarak, tek iş parçacıklı davranış tutarlılığı elde edebilirsiniz - ana iş parçasındaki başka hiçbir komut dosyasının veya sistemin üzerinde çalışmakta olduğunuz verileri değiştiremeyeceğini bilmek.
Verim dönüş hattı size birkaç seçenek sunar. Yapabilirsin...
yield return null
Bir sonraki karenin Güncellemesinden sonra devam etmek ()
yield return new WaitForFixedUpdate()
bir sonraki FixedUpdate () işleminden sonra devam etmek için
yield return new WaitForSeconds(delay)
belirli bir oyun süresi geçtikten sonra devam etmek
yield return new WaitForEndOfFrame()
GUI oluşturma işlemini tamamladıktan sonra devam etmek için
yield return myRequest
burada myRequest
bir WWW örneği, istenen veri web veya diskten yüklenmeyi tamamladıktan sonra devam etmek için.
yield return otherCoroutine
nerede otherCoroutine
bir olduğunu eşyordam örneği sonra devam edilecek, otherCoroutine
tamamlanıncaya. Bu genellikle, yield return StartCoroutine(OtherCoroutineMethod())
yürütme zincirinin, istediği zaman üretebileceği yeni bir korotine zincirlenmesi için kullanılır.
Deneysel olarak, ikinci atlamayı atlamak ve aynı bağlamda zincirleme yürütmek istiyorsanız, StartCoroutine
basitçe yazma yield return OtherCoroutineMethod()
aynı amacı gerçekleştirir.
Bir iç tamamlayan StartCoroutine
ikinci bir nesne ile birlikte iç içe eşyordam çalıştırmak istiyorsanız hala gibi yararlı olabiliryield return otherObject.StartCoroutine(OtherObjectsCoroutineMethod())
... coroutinin bir sonraki dönüşünü ne zaman yapmasını istediğine bağlı olarak.
Veya yield break;
korotinin sonuna gelmeden önce, return;
geleneksel bir yönteme erken gitmek için kullanabileceğiniz şekilde durdurmak için .