내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-10 05:28

제목

[C#] Task.Run 과 Task.Factory.StartNew


work 4.5에서부터 스레드를 만드는 방법으로 Task.Run 메소드를 지원한다. 이는 그 이전까지 사용하던 Task.Factory.StartNew를 보다 가볍게 사용 할 목적으로 만들었다고 한다. 새로운 메소드를 제공한다고 StartNew를 폐기한다는 것은 아니며 간편하게 사용하기 위한 추가적인 메소드를 제공한다고 한다.

결론부터 말하지면, 스레드 내부에서 관리가 필요한 자식 스레드를 생성하지 않고, 백그라운드에서 가볍게 처리해야 할 스레드가 필요하다면 가급적 Thread.Run을 사용하는 것이 편리 할 것이다.

Task.Run 과 Task.Factory.StartNew

Task.Run(MathodA)은 기본적으로 다음과 동일하다.

Task.Factory.StartNew(
    MathodA
    , CancellationToken.None
    , TaskCreationOptions.DenyChildAttach
    , TaskScheduler.Default
);

이는 Task.Factory.StartNew(MathodA)가 다음의 기본 실행옵션을 갖는 것과 차이가 있다.

Task.Factory.StartNew(
    MathodA
    , CancellationToken.None
    , TaskCreationOptions.None
    , TaskScheduler.Current
);

어떻게 차이가 난다는 건가?

1. DenyChildAttach

아래 코드에서 parentTask.Wait()는 내부의 childTask에 영향을 주지 않는다. 스레드 내부에서 생성한 하위태스크의 관리가 필요한 경우 상태관리를 하기가 불편할 것이다.

// ref :  https://stackoverflow.com/a/55949173
var parentTask = Task.Run(() =>
{
    var childTask = new Task(() =>
    {
        Thread.Sleep(10000);
        Console.WriteLine("Child task finished.");
    }, TaskCreationOptions.AttachedToParent);
    childTask.Start();

    Console.WriteLine("Parent task finished.");
});

parentTask.Wait();
Console.WriteLine("Main thread finished.");

2. TaskScheduler.Default 와 TaskScheduler.Current

Task.Factory.StartNew의 기본 스케쥴러는 Current이다. UI스레드에서 생성한 Task는 작업 스케쥴러를 UI스레드와 같이 사용 할 수 있으며, 이는 백그라운드에서 업데이트가 잦은 동작을 할 경우 UI 업데이트를 멈추게 할 수도 있을 것이다.

따라서 기본값으로 백그라운드 스레드를 생성한다면 Task.Run 이 좀 더 좋은 선택이 될 수 있다.

3. 그 외에도..

Task.Factory.StartNew는 async delegate를 이해하지 못한다거나, ThrowUnobservedTaskExceptions 설정에 따라 스레드 내부에서 발생한 예외를 통지받지 목하는 경우도 있다고 한다.

그래서 결국은 꼭 필요한 상황이 아니라면 Task.Factory.StartNew를 사용하지 말자는 의견을 볼 수 있었다.

참고링크


출처1

https://ivorycirrus.github.io/TIL/csharp-task-run/

출처2