컬렉션이란?

프로그래밍을 통하여 어플리케이션을 제작할 때, 대부분의 경우 특정 개체나, 값의 그룹을 만들고 관리하여야 할 필요가 있다. 개체의 그룹을 만들고 관리하는 방법에는 배열을 만들거나 컬렉션을 만드는 두 가지 방법이 있다.

C#의 기본 배열은 크기가 고정된 배열을 만들어 관리하는데 유리하지만, 크기를 변경하려면 새로운 배열을 재할당하여야 한다.

컬렉션은 개체 그룹에 대해 작업하는 보다 유연한 방법을 제공한다. 그룹의 크기를 동적으로 확장/축소할 수 있으며, 일부 그룹의 경우 컬렉션에 들어가는 개체에 키를 할당하여 개체를 신속하게 검색할 수 있다.

 

컬렉션의 종류

닷넷에서 사용하는 컬렉션들은 여러 네임스페이스에 분산되어 있다.

System.Collection.Generic

  • Dictionary<Tkey, TValue>
    • Tkey 값을 해시 함수로 해싱하여 해시테이블을 구현한 키/값 쌍의 컬렉션이다.
  • List<T>
    • 인덱스로 엑세스할 수 있는 개체 목록을 나타낸다.
    • 제공된 다양한 메서드를 사용하여 목록의 검색/정렬/수정을 진행할 수 있다.
  • Queue<T>
    • 선입선출 방식의 개체 컬렉션을 나타낸다.
  • Stack<T>
    • 후입선출 방식의 개체 컬렉션을 나타낸다.
  • SortedList<TKey,TValue>
    • IComparer<T> 구현을 기반으로 한, 키에 따라 정렬된 키/값 쌍의 컬렉션을 나타낸다.

 

System.Collections

System.Collections 네임스페이스의 클래스는 제네릭 타입이 아닌 Object 형식의 개체로 요소를 저장하기때문에,

가능하면, 해당 네임스페이스의 레거시 형식 대신 System.Collection.Generic의 제네릭 컬렉션을 사용하여야한다.

  • ArrayList : 필요에 따라 크기가 동적으로 증가하는 개체 배열
  • Hashtable : 키의 해시 코드에 따라 구성괸 키/값 쌍의 컬렉션
  • Queue : 선입선출 방식의 큐 컬렉션
  • Stack : 선입선출 방식의 스택 컬렉션

System.Collections.Concurrent

.Net Framework 4 이상 버전에서 사용가능한 System.Collections.Concurrent 네임스페이스의 컬렉션은. 멀티스레드 연산에서 안전하게 엑세스할 수 있는 컬렉션들을 제공한다.

  • BlockingCollection<T>
  • ConcurrentDictionary<TKey, TValue>
  • ConcurrentQueue<T>
  • ConcurrentStack<T>

등의 컬렉션이 있다.

같이 보기

https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/collections#BKMK_Concurrent

 

컬렉션(C#)

개체 그룹 작업에 사용되는 C#의 컬렉션에 대해 알아봅니다. 애플리케이션의 요구가 변경됨에 따라 컬렉션이 동적으로 확장되거나 축소될 수 있습니다.

docs.microsoft.com

 

코루틴이란?

코루틴을 사용하면 여러 프레임에 현재 함수의 작업을 분산하여 진행할 수 있다. 함수 실행 중 yield return을 사용하여 작업을 일시 중단한 후, 다른 프레임/시간에 제어권을 다시 넘겨받아 사용하는 식이다.

 

쓰레드와의 차이점은, 코루틴은 메인 스레드상에서 수행된다는 것이다. 

쓰레드의 경우 둘, 혹은 여러개의 쓰레드가 각자의 작업을 맡아 수행한다면,

코루틴의 경우 한 개의 쓰레드가 ABABABAB...형식으로 각각의 작업을 조금씩 나누어 수행한다.

쓰레드와 코루틴의 동작 차이

쓰레드

  • 별개 쓰레드에서 동작한다.
  • 동시에 여러개의 일을 처리할 수 있다.
  • 쓰레드는 선점형이다.
    • 일을 하는동안에도 다른 쓰레드가 돌아가고 있다.
    • 공유 메모리를 사용할 경우, 서로의 접근이 겹칠 수 있다.
      • Lock을 사용할 경우, 먼저 접근한 쓰레드가 우선적으로 사용하게 된다.
  • 비동기적이다 = 동시에 수행된다.

코루틴

  • 단일 쓰레드에서 동작한다.
  • 여러개의 일을 나누어, 하나씩 처리한다.
  • 코루틴은 비선점형이다.
    • 현재 코루틴 동작이 끝날때까지, 다른 코루틴들은 대기하게 된다.
    • 동시에 동작하지 않으므로, 메모리 접근이 겹칠 일이 없다.
      • 현재 동작하고 있는 코루틴이 메모리를 사용하고 있을 것이다.
  • 비동기적이 아니다 = 동시에 수행되지 않는다.

코루틴 선언법

    IEnumerator ParticleFadeOut()
    {
        SpriteRenderer Renderer = this.GetComponent<SpriteRenderer>();
        Color color = Renderer.color;
        while(color.a > 0.0f)
        {
            color.a -= 0.2f;
            Renderer.color = color;
            yield return new WaitForSeconds(0.1f);
        }
        
    }
  • 코루틴의 리턴 타입은 IEnumerator(열거자)로 선언한다.
  • 함수 동작 중 수행을 중단할 때, yield return으로 return한다.
    • 해당 방식으로 리턴할 경우, 그 위치에서 활동이 중단된 후 다시 돌아온다.
  • Yield의 종류는 다음과 같다
  • yield return null; -> 다음 프레임에 바로 시작
  • yield return new WaitForSeconds(float) -> 일정 시간동안 대기
  • yield return break; -> 코루틴 종료
  • yield return new WaitForEndOfFrame();
    • 모든 카메라와 GUI가 렌더링을 완료한, 프레임의 바로 직전에 다시 실행한다.
    • 현재 화면을 저장하여 활용할 필요가 있을때 사용할 수 있다.
  • yield return new WaitForFixedUpdate();
    • 다음 FixedUpdate()가 호출될 때까지 기다린다.
  • yield return new WaitUntil(조건문);
    • 해당 조건문이 true가 될 때까지 기다린다.
    • 조건문은 Update ~ LateUpdate 사이에 실행되어진다.
  • yield return new WaitWhile(조건문);
    • 해당 조건문이 true인 동안 기다린다
    • 조건문은 Update ~ LateUpdate 사이에 실행된다.

코루틴의 사용법

//호출방법
StartCoroutine(ParticleFadeOut());
StartCoroutine("ParticleFadeOut");

//중단방법
Coroutine particleCorutine;
particleCorutine = StartCoroutine(ParticleFadeOut());
StopCoroutine(particleCorutine);
  • 코루틴 호출시에는, 함수명을 호출하거나 함수명을 String으로 호출하는 형태로 선언한다.
  • 코루틴 중지시에는 Corutine 변수가 필요하므로, 중단할 필요가 있을 경우 미리 선언하여 코루틴 시작 시 저장해둔다.

주의 사항

  • 코루틴이 돌아가고 있던 객체가 파괴될 시에는 코루틴이 자동으로 중단되지만, 스크립트가 Disable될 때에는 중단되지 않는다.
    • 스크립트가 중단될 일이 있을 경우 별도의 종료 호출이 필요하다.
  • 오브젝트가 활성화 되어있지 않은 상태에서 코루틴이 활성화될 경우 에러가 발생할 수 있다.
    • 오브젝트를 생성(Instantiate)된 직후에 별도의 함수로 코루틴을 호출할 경우, 에러가 발생할 수 있다.
    • 프리팹으로 생성한 오브젝트에서 코루틴을 호출할 일이 있다면, Start()에서 코루틴을 호출하게 만들어 확실히 생성된 후 코루틴을 생성하게 만드는 것이 좋을것이다.

코루틴 사용의 장점

  • Update 루프를 최적화 할 수 있다.
  • 코드 정리를 수행할 수 있다.

코루틴 사용의 단점

  • 가비지가 많이 생성된다.
    • StartCoroutine을 사용할 때, 엔진 내부적으로 가비지가 다량 생성된다고 한다. -> 확인 필요
    • 위의 소스 코드를 확인하면, yield return new ~ 의 형식으로 대기가 진행됨을 알 수 있다. yield return이 진행될때마다 새로운 인스턴스이 생성되기 때문에, 가비지 생성 문제가 생기게된다.
      • 해당 문제를 해결하기 위해, Wait 인스턴스를 미리 만들어둔 뒤 캐싱하여 사용할 수 있다.

 

같이 보기

https://docs.unity3d.com/Manual/Coroutines.html

 

Unity - Manual: Coroutines

Coroutines A coroutine allows you to spread tasks across several frames. In Unity, a coroutine is a method that can pause execution and return control to Unity but then continue where it left off on the following frame. In most situations, when you call a

docs.unity3d.com

 

'Programming > Unity' 카테고리의 다른 글

유니티 오브젝트 파괴 / Gameobject.Destroy()  (0) 2022.03.02

함수 선언

public static void Destroy ( obj , t = 0.0F);

  • UnityEngine.object Obj : 삭제할 object
  • [DefaultValue("0.0F")] float t : 해당 시간이 지난 이후 삭제, 기본값일 경우(= 0.0) 현재 Update Loop가 끝난 후 삭제된다. 

사용

    public void OnMouseUp()
    {
        Destroy(this.gameObject);
    }

Node 오브젝트들에 해당 함수를 구현하고 사용하고 오브젝트 클릭시, 다음과 같이 삭제됨을 확인할 수 있었다.

클릭한 오브젝트가 삭제됨

  • Destroy() 함수가 호출될 시, OnDisable()과 OnDestroy()가 호출된다.
    • 삭제시 수행할 작업이 있다면 해당 함수를 구현하여 처리할 수 있다.
public void OnMouseUp()
{
	Debug.Log("Call Destroy Function");
	Destroy(this.gameObject);
	Debug.Log("Call Destroy Function End");
}

public void OnDestroy()
{
	Debug.Log("OnDestroy");
}

public void OnDisable()
{
	Debug.Log("OnDisable");
}

위 방식으로 실행한 결과 Log

주의 사항

  • 스크립트 내부에서 Destroy(this) 로 삭제를 구현할시 해당 클래스, 즉 스크립트만 삭제됨을 확인할 수 있다.

이렇게 되어버린다

  • 게임오브젝트를 다른 곳에서 리스트에 넣어서 관리하고 있었을 때, 삭제 후 해당 오브젝트를 관리할떄 조심해야 한다
    • GameObject로 비교 시 null값이 나오지만, object로 비교시에는 GC가 메모리를 초기화해주기 전까지 null값이 나오지 않는다.(Fake NULL 이슈)
Debug.Log("Check!");

if ((GameObject)NodeBoard[0, 0] == null)
	Debug.Log("Null GameObject Found!!!");
if ((object)NodeBoard[0, 0] == null)
	Debug.Log("Null Object Found!!!");
if (!NodeBoard[0, 0])
	Debug.Log("Null by BOOLcheck Found!!!");
    
Debug.Log("Check End!");

삭제 이후 Log, object 비교는 실패한다.

  • 같은 이유로, 소멸자도 삭제 이후에 따로 출력된다.

4초 후 호출된 소멸자

같이보기

https://docs.unity3d.com/ScriptReference/Object.Destroy.html

 

Unity - Scripting API: Object.Destroy

The object obj is destroyed immediately after the current Update loop, or t seconds from now if a time is specified. If obj is a Component, this method removes the component from the GameObject and destroys it. If obj is a GameObject, it destroys the GameO

docs.unity3d.com

 

NOTE

  • Fake Null 이슈에 관해서는 더 깊게 정리해둘 필요가 있을 듯.

 

'Programming > Unity' 카테고리의 다른 글

유니티 코루틴 / Unity Coroutine  (0) 2022.03.11

+ Recent posts