업데이트 : 2018 년 Unity는 작업 을 오프로드하고 여러 CPU 코어를 사용하는 방법으로 C # 작업 시스템 을 출시하고 있습니다.
아래의 답변은이 시스템보다 우선합니다. 여전히 작동하지만 필요에 따라 최신 Unity에서 더 나은 옵션을 사용할 수 있습니다. 특히, 작업 시스템은 아래에 설명 된 수동으로 작성된 스레드가 안전하게 액세스 할 수있는 것에 대한 일부 제한 사항을 해결하는 것으로 보입니다. 예를 들어, 레이 캐스트를 수행하고 메시를 병렬로 구성하는 미리보기 보고서를 실험하는 개발자 .
이 작업 시스템을 사용한 경험이있는 사용자를 초대하여 엔진의 현재 상태를 반영한 고유 한 답변을 추가합니다.
과거에는 Unity에서 무거운 작업에 스레딩을 사용했지만 (일반적으로 이미지 및 지오메트리 처리) 다른 C # 응용 프로그램에서 스레드를 사용하는 것과 크게 다르지 않습니다.
Unity는 다소 오래된 .NET 하위 집합을 사용하기 때문에 사용할 수없는 새로운 스레딩 기능과 라이브러리가 있지만 기본 사항이 모두 있습니다.
Almo가 위의 주석에서 언급했듯이 많은 Unity 유형은 스레드 안전하지 않으며 주 스레드에서 구성, 사용 또는 비교하려고하면 예외가 발생합니다. 명심해야 할 사항 :
한 가지 일반적인 경우는 멤버에 액세스하기 전에 GameObject 또는 Monobehaviour 참조가 null인지 확인하는 것입니다. myUnityObject == null
UnityEngine.Object의 하위 항목에 대해 오버로드 된 연산자를 호출하지만 System.Object.ReferenceEquals()
이 문제를 어느 정도 해결합니다. Destroy () ed GameObject는 오버로드를 사용하여 null과 같지만 아직 ReferenceEqual이 아니라는 점을 기억하십시오.
Unity 타입에서 파라미터를 읽는 것은 일반적으로 다른 스레드에서 안전합니다 (위와 같이 null을 확인하는 한 조심스럽게 예외를 throw하지는 않습니다). 그러나 여기 에서 메인 스레드가 상태를 수정하고 있다는 필립의 경고에 주목하십시오. 당신이 그것을 읽는 동안. 일관성이없는 상태를 읽는 것을 피하기 위해 누가 무엇을 언제 수정해야하는지에 대해 훈련을 받아야합니다. 이로 인해 버그가 발생할 수 있습니다. 마음대로 재생산하지 않습니다.
임의 및 시간 정적 멤버는 사용할 수 없습니다. 임의성이 필요한 경우 스레드 당 System.Random 인스턴스를 작성하고 타이밍 정보가 필요한 경우 System.Diagnostics.Stopwatch 인스턴스를 작성하십시오.
Mathf 함수, Vector, Matrix, Quaternion 및 Color 구조체는 스레드에서 모두 잘 작동하므로 대부분의 계산을 개별적으로 수행 할 수 있습니다.
메인 오브젝트에서 게임 오브젝트 생성, 모노 동작 부착, 텍스쳐, 메시, 머티리얼 생성 / 업데이트가 모두 필요합니다. 과거에 이러한 작업을 수행해야 할 때 작업자 스레드가 원시 데이터를 준비하는 생산자-소비자 대기열을 설정했습니다 (메시 또는 텍스처에 적용 할 벡터 / 컬러 배열). 메인 스레드의 업데이트 또는 코 루틴은 데이터를 폴링하여 적용합니다.
그 노트를 벗어난 상태에서, 내가 스레드 작업에 자주 사용하는 패턴이 있습니다. 나는 그것이 최선의 연습 스타일이라는 것을 보장하지는 않지만 작업을 완료합니다. (개선을위한 의견이나 편집은 환영합니다-스레딩은 기본 사항 만 알고있는 매우 깊은 주제라는 것을 알고 있습니다)
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.
}
}
작업 속도를 높이기 위해 스레드간에 작업을 엄격하게 분할 할 필요가없고 비 차단 방식으로 게임의 나머지 부분이 계속 똑딱 거리는 방법을 찾고 있다면 Unity의 더 가벼운 솔루션은 Coroutines 입니다. 이러한 기능은 일부 작업을 수행 한 다음 엔진으로 다시 제어하여 작업을 계속하고 나중에 원활하게 재개 할 수있는 기능입니다.
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...
}
}
}
엔진은 (내가 알 수있는 한) 파괴 된 물체에서 코 루틴을 제거하기 때문에 특별한 정리 고려 사항이 필요하지 않습니다.
메소드의 모든 로컬 상태는 생성되고 재개 될 때 유지되므로 많은 목적을 위해 다른 스레드에서 중단없이 실행되는 것처럼 보입니다 (그러나 주 스레드에서 실행하는 모든 편의는 제공됩니다). 메인 스레드가 부당하게 느려지지 않을 정도로 짧을 때마다 확인해야합니다.
중요한 작업이 수율로 분리되지 않도록하여 단일 스레드 동작의 일관성을 얻을 수 있습니다. 기본 스레드의 다른 스크립트 나 시스템이 작업중인 데이터를 수정할 수 없다는 것을 알고 있습니다.
수익률 반환 라인은 몇 가지 옵션을 제공합니다. 당신은 할 수 ...
코 루틴이 다음 차례를 원할 때에 따라
또는 yield break;
코 루틴이 끝날 때까지 멈추기 위해 return;
기존 방법을 일찍 사용 하는 방법.