갓똥
나는야 프로그래머
갓똥
전체 방문자
오늘
어제
  • 분류 전체보기 (186)
    • 프로그래밍 (146)
      • 자바 (9)
      • 안드로이드 (2)
      • 유니티 (20)
      • C++ (38)
      • C# (56)
      • HTML (2)
      • 파이썬 (3)
      • 자료구조 (2)
      • 알고리즘 (0)
      • 문제풀이 (4)
      • 디자인 패턴 (7)
      • 카카오톡 봇 (1)
      • 엑셀 (1)
      • 기타 (1)
    • 게임 (21)
      • 테일즈위버 (0)
      • 카이로소프트 (1)
      • 순위 (19)
      • 기타 (1)
    • 일상 (13)
      • 카페 (1)
      • 방탈출 (12)
    • 기타 (6)
      • 웃긴자료 (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

태그

  • C# 예외 처리
  • 글로벌게임매출
  • C++ 소멸자
  • C# boxing
  • 강남 방탈출
  • 모바일 게임 순위
  • 롤 골드그래프
  • 게임매출순위
  • 전세계게임매출순위
  • c# coroutine
  • pc 게임 순위
  • 게임 매출 순위
  • 유니티 그래프
  • 자바
  • 유니티 그래프 그리기
  • c# unboxing
  • c# 코루틴
  • c# delegate
  • Unity Graph
  • 게임 디자인 패턴
  • C++ virtual
  • pc게임 순위
  • c# Thread
  • C++ 상속
  • 전세계 게임 매출
  • C++
  • 2020년 게임 매출
  • 알고리즘
  • 유니티 골드그래프
  • c# collection

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
갓똥

나는야 프로그래머

[C#] Task 클래스
프로그래밍/C#

[C#] Task 클래스

2020. 5. 10. 17:29
728x90
반응형

1. 핵심 정리

using System;
using System.Threading;
using system.Threading.Tasks;

class Program {
    public static void Foo() {
        Console.WriteLine($"Foo : {Thread.CurrentThread.ManagedThreadID}");
        Thread.Sleep(3000);
    }
    
    public static void Main() {
        Thread t = new Thread(Program.Foo);
        t.Start();
        
        Task t = Task.Run(Program.Foo);
        
        Console.ReadKey();
    }
}

 

스레드를 만들어 사용하는 코드이다.
위의 코드에서 12~13번 라인의 코드와 15번 라인의 코드는 동일한 작업을 수행한다.
스레드 객체를 만들어 수행하는 것이다.
그렇다면 차이는 무엇일까?

 

using System;
using System.Threading;
using system.Threading.Tasks;

class Program {
    public static void Foo() {
        Console.WriteLine($"Foo : {Thread.CurrentThread.ManagedThreadID}");
        Thread.Sleep(3000);
    }
    
    public static void Main() {
        for(int i = 0; i < 20; i++) {
            Thread t = new Thread(Program.Foo);
            t.Start();
        }
        
        // Task t = Task.Run(Program.Foo);
        
        Console.ReadKey();
    }
}

 

한 번 for문을 이용해 20번 반복한다고 해보자.
그렇다면 분명 20개의 스레드가 만들어서 돌텐데
그리고 실행해보면 20개의 ID값도 다 다르고 정상 동작한다.

하지만 가령 CPU가 듀얼코어라면 정말 동시에 실행되고 있는 것은 2개밖에 없을 것이다.
나머지는 왔다갔다 하면서 작업을 수행하게 된다.
그런데 이 왔다갔다 하는 과정에서 성능저하가 있을 수 있다.
그래서 스레드는 무작정 많이 만드는 것보단 적당량을 만들고 또 스레드가 필요하다면
작업을 큐에 넣어놨다가 작업을 마치고 대기중인 스레드를 통해 다시 작업을 수행하게 하는게 좋다.

흔히 그렇게 관리하는것들을 스레드 풀이라고 부른다.

for문 내부는 무작정 스레드 객체를 만드는 것이고
Task는 시스템이 스레드 풀을 만들어 최적의 코드로 작성해준다.
따라서 for문에 Task를 넣고 돌려보면 CPU마다 다르지만 사용했던 스레드가 작업이 끝나면
다시 작업을 수행하는 모습을 볼 수 있다.(ID가 같음)

 ① Task

    => 스레드 풀(thread pool)에 있는 스레드를 사용해서 메소드 수행

 


2. 세부 내용

using System;
using System.Threading;
using System.Threading.Tasks;

class Program {
    public static void F1() {
        Console.WriteLine("F1 Start");
        Thread.Sleep(1000);
        Console.WriteLine("F2 End");
    }
    
    public static void Main() {
        Task t = Task.Run(F1);
        // t.Wait();
    }
}

 

위의 코드를 실행해보면 어떠한 것도 뜨지 않고 종료되는 것을 볼 수 있다.
왜냐하면 Task는 기본적으로 백그라운드 스레드라 그렇다.
주 스레드가 종료되면 자동적으로 종료되기 때문이다.
Task로 만든 스레드를 대기시키려면 Wait()이란 메소드가 있다.

 ① 종료를 대기하려면 t.Wait() 사용

 

using System;
using System.Threading;
using System.Threading.Tasks;

class Program {
    public static void F1(object obj) {
        Console.WriteLine("F1 Start");
        Thread.Sleep(1000);
        Console.WriteLine("F2 End");
    }
    
    public static void Main() {
        Task t = Task.Run(() => F1("hello");
        // t.Wait();
    }
}

 

만약 메소드가 인자가 있는 메소드라면 앞선 포스트와 같이
람다 표현식을 사용해서 해결할 수 있다.

 ② 인자가 있는 메소드라면 람다 표현식 활용

 

using System;
using System.Threading;
using System.Threading.Tasks;

class Program {
    public static void F1(object obj) {
        Console.WriteLine("F1 Start");
        Thread.Sleep(1000);
        Console.WriteLine("F2 End");
    }
    
    public static void Main() {
        Task t = Task.Run(() => F1("hello");
        
        Console.WriteLine(t.IsCompleted); // false
        t.Wait();
        Console.WriteLine(t.IsCompleted); // true
    }
}

 

현재 스레드가 동작 중인지 확인하는 방법으로는 IsCompleted가 있다.

 ③ 스레드가 동작 중인지, 살아있는 스레드인지 확인할 땐 .IsCompleted

 

using System;
using System.Threading;
using System.Threading.Tasks;

class Program {
    public static int F1(object obj) {
        Console.WriteLine("F1 Start");
        Thread.Sleep(1000);
        Console.WriteLine("F2 End");
        
        return 1;
    }
    
    public static void Main() {
        Task<int> t = Task.Run(() => F1("hello");
        
        Console.WriteLine("Before Result");
        Console.WriteLine(t.Result);
        Console.WriteLine("After Result");
    }
}

 

만약 반환 타입이 있는 메소드라면 Task<int>로 만들면 된다.
결과 값은 t.Result 멤버로 받을 수 있다.
t.Result를 수행하는 코드가 메소드가 끝나기전에 수행될 수 있는데 걱정할 필요 없다.
t.Result는 메소드가 끝나길 대기하다가 결과를 출력하게 된다.
테스트를 위해 위와 같이 코드를 짜고 돌려보면
Before Result -> F1 Start -> (1초 대기) -> F1 End -> 1 -> After Result
로 나오게 된다.

 ④ Task vs Task<T>

    => 스레드로 수행할 메소드의 반환 값이 있다면 Task<T> 사용

728x90
반응형

'프로그래밍 > C#' 카테고리의 다른 글

[C#] 쓰레기 수집기 (Garbage Collector)  (0) 2020.05.16
[C#] Dispose() 메소드  (0) 2020.05.11
[C#] 스레드 클래스 멤버  (0) 2020.05.08
[C#] 스레드 개념 (Thread)  (0) 2020.05.08
[C#] Fluent vs Query (LINQ Fluent vs Query Syntax)  (0) 2020.05.07
    '프로그래밍/C#' 카테고리의 다른 글
    • [C#] 쓰레기 수집기 (Garbage Collector)
    • [C#] Dispose() 메소드
    • [C#] 스레드 클래스 멤버
    • [C#] 스레드 개념 (Thread)
    갓똥
    갓똥
    공부하며 알아가는 내용을 정리해 봅니다.

    티스토리툴바