반응형

설명

Task 클래스는 반환 하지 않는 값을 지정 하 고는 일반적으로 단일 작업을 비동기적으로 실행 합니다. Task 개체는의 중앙 구성 요소 중 하나는 작업 기반 비동기 패턴 .NET Framework 4에서 처음 도입 된 합니다. 작업을 수행 하므로 Task 개체 일반적으로 비동기적으로 실행 스레드 풀 스레드에서 동기적으로 주 애플리케이션 스레드에서 사용할 수 있습니다 것이 아니라 합니다 Status 속성인 뿐만 IsCanceled, IsCompleted, 및 IsFaulted 속성에는 작업의 상태를 확인 합니다. 가장 일반적으로 작업을 수행 하는 작업을 지정 하는 람다 식 사용 됩니다.

사용할 값을 반환 하는 작업의 경우는 Task<TResult> 클래스입니다.

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

class Example
{
    static void Main()
    {
        Action<object> action = (object obj) =>
                                {
                                   Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                   Task.CurrentId, obj,
                                   Thread.CurrentThread.ManagedThreadId);
                                };

        // Create a task but do not start it.
        Task t1 = new Task(action, "alpha");

        // Construct a started task
        Task t2 = Task.Factory.StartNew(action, "beta");
        // Block the main thread to demonstrate that t2 is executing
        t2.Wait();

        // Launch t1 
        t1.Start();
        Console.WriteLine("t1 has been launched. (Main Thread={0})",
                          Thread.CurrentThread.ManagedThreadId);
        // Wait for the task to finish.
        t1.Wait();

        // Construct a started task using Task.Run.
        String taskData = "delta";
        Task t3 = Task.Run( () => {Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                                     Task.CurrentId, taskData,
                                                      Thread.CurrentThread.ManagedThreadId);
                                   });
        // Wait for the task to finish.
        t3.Wait();

        // Construct an unstarted task
        Task t4 = new Task(action, "gamma");
        // Run it synchronously
        t4.RunSynchronously();
        // Although the task was run synchronously, it is a good practice
        // to wait for it in the event exceptions were thrown by the task.
        t4.Wait();
    }
}
// The example displays output like the following:
//       Task=1, obj=beta, Thread=3
//       t1 has been launched. (Main Thread=1)
//       Task=2, obj=alpha, Thread=4
//       Task=3, obj=delta, Thread=3
//       Task=4, obj=gamma, Thread=1

분리 작업 만들기 및 실행

Task 클래스는 또한 작업을 초기화 하는 하지만 해당 실행에 대 한 예약 하지 않습니다 하는 생성자를 제공 합니다. 성능상의 이유로 합니다 Task.Run 또는 TaskFactory.StartNew 메서드를 만들고 계산 태스크를 예약 하기 위한 기본 메커니즘입니다 하지만 생성 및 일정 예약을 구분 해야 합니다는 시나리오에 대 한 생성자를 사용 하 여를 호출 합니다 Task.Start 나중에 실행에 대 한 작업을 예약 하는 방법입니다.

 

하나 이상의 작업이 완료 되기를 기다리는

작업 일반적으로 스레드 풀 스레드에서 비동기적으로 실행, 때문에 작업을 인스턴스화해야 하는 즉시 만들고 작업을 시작 하는 스레드 실행을 계속 합니다. 일부 경우에 호출 스레드는 주 애플리케이션 스레드의 경우 앱을 종료할 수 있습니다 보다 먼저 태스크 실제로 실행을 시작 합니다. 다른 애플리케이션의 논리는 하나 이상의 작업 실행을 완료 하는 경우에 호출 스레드가 계속 실행 필요할 수 있습니다. 호출 스레드의 실행을 동기화 할 수 있습니다 및 비동기 작업이 출시를 호출 하 여를 Wait 메서드를 하나 이상의 작업이 완료 될 때까지 기다립니다.

완료 하는 단일 작업에 대 한 대기를 호출 하면 해당 Task.Wait 메서드. 에 대 한 호출을 Wait 메서드는 단일 클래스 인스턴스 실행이 완료 될 때까지 호출 스레드를 차단 합니다.

다음 예제에서는 매개 변수가 없는 호출 Wait() 작업이 완료 될 때까지 무조건 대기 하는 방법입니다. 태스크를 호출 하 여 작업을 시뮬레이트하는 Thread.Sleep 2 초 대기 하는 방법입니다.

 

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

class Program
{
    static Random rand = new Random();

    static void Main()
    {
        // Wait on a single task with no timeout specified.
        Task taskA = Task.Run( () => Thread.Sleep(2000));
        Console.WriteLine("taskA Status: {0}", taskA.Status);
        try {
          taskA.Wait();
          Console.WriteLine("taskA Status: {0}", taskA.Status);
       } 
       catch (AggregateException) {
          Console.WriteLine("Exception in taskA.");
       }   
    }    
}
// The example displays output like the following:
//     taskA Status: WaitingToRun
//     taskA Status: RanToCompletion

또한 조건에 따라 작업이 완료 되기를 기다릴 수 있습니다. 합니다 Wait(Int32)  Wait(TimeSpan) 메서드는 작업이 완료 될 때까지 호출 스레드를 차단 또는 먼저 도달 하는 시간 제한 간격이 경과 합니다. 다음 예제에서는 2 초 동안 대기 하지만 해당 호출 스레드는 차단 시간 제한이 만료 될 때까지 1 초 제한 시간 값을 정의 하는 작업을 시작 하므로 전과 작업 실행이 완료 합니다.

 

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

public class Example
{
   public static void Main()
   {
      // Wait on a single task with a timeout specified.
      Task taskA = Task.Run( () => Thread.Sleep(2000));
      try {
        taskA.Wait(1000);       // Wait for 1 second.
        bool completed = taskA.IsCompleted;
        Console.WriteLine("Task A completed: {0}, Status: {1}",
                         completed, taskA.Status);
        if (! completed)
           Console.WriteLine("Timed out before task A completed.");                 
       }
       catch (AggregateException) {
          Console.WriteLine("Exception in taskA.");
       }   
   }
}
// The example displays output like the following:
//     Task A completed: False, Status: Running
//     Timed out before task A completed.

 

호출 하 여 취소 토큰을 제공할 수도 있습니다는 Wait(CancellationToken)  Wait(Int32, CancellationToken) 메서드. 경우 토큰의 IsCancellationRequested 속성은 true 는 더 이상 true 하는 동안 합니다 Wait 메서드를 실행, 메서드가 throw는 OperationCanceledException합니다.

경우에 따라 대기 하려는 싶지만 완료 하는 일련의 작업을 실행 중 첫 번째 작업 하는 주의 해야입니다. 이 위해 수 중 하나를 호출의 오버 로드는 Task.WaitAny 메서드. 다음 예제에서는 난수 생성기에서 간격 결정에 대 한 절전 모드로 전환 되는 각 세 가지 작업을 만듭니다. WaitAny(Task[]) 메서드 첫 번째 작업이 완료 되기를 기다립니다. 다음 예제에서는 세 작업의 상태에 대 한 정보를 표시합니다.

 

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

public class Example
{
   public static void Main()
   {
      var tasks = new Task[3];
      var rnd = new Random();
      for (int ctr = 0; ctr <= 2; ctr++)
         tasks[ctr] = Task.Run( () => Thread.Sleep(rnd.Next(500, 3000)));

      try {
         int index = Task.WaitAny(tasks);
         Console.WriteLine("Task #{0} completed first.\n", tasks[index].Id);
         Console.WriteLine("Status of all tasks:");
         foreach (var t in tasks)
            Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
      }
      catch (AggregateException) {
         Console.WriteLine("An exception occurred.");
      }
   }
}
// The example displays output like the following:
//     Task #1 completed first.
//     
//     Status of all tasks:
//        Task #3: Running
//        Task #1: RanToCompletion
//        Task #4: Running

일련의 작업을 호출 하 여 완료 모든 않을 수도 있습니다는 WaitAll 메서드. 다음 예제에서는 10 개의 작업을 만드는, 대기를 완료 하려면 모든 10에 대 한 다음 해당 상태를 표시 합니다.

 

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

public class Example
{
   public static void Main()
   {
      // Wait for all tasks to complete.
      Task[] tasks = new Task[10];
      for (int i = 0; i < 10; i++)
      {
          tasks[i] = Task.Run(() => Thread.Sleep(2000));
      }
      try {
         Task.WaitAll(tasks);
      }
      catch (AggregateException ae) {
         Console.WriteLine("One or more exceptions occurred: ");
         foreach (var ex in ae.Flatten().InnerExceptions)
            Console.WriteLine("   {0}", ex.Message);
      }   

      Console.WriteLine("Status of completed tasks:");
      foreach (var t in tasks)
         Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
   }
}
// The example displays the following output:
//     Status of completed tasks:
//        Task #2: RanToCompletion
//        Task #1: RanToCompletion
//        Task #3: RanToCompletion
//        Task #4: RanToCompletion
//        Task #6: RanToCompletion
//        Task #5: RanToCompletion
//        Task #7: RanToCompletion
//        Task #8: RanToCompletion
//        Task #9: RanToCompletion
//        Task #10: RanToCompletion

 

하나 이상의 작업이 완료 되기를 기다릴 때 호출 하는 스레드에서 실행 중인 작업에서 throw 된 예외 전파는 참고를 Wait 메서드를 다음 예제와 같이 합니다. 정상적으로 완료 중 3 개는 12 작업 및 세 가지 예외는 throw를 시작 합니다. 나머지 6 개 작업 중 세 개는 시작 하기 전에 취소 되 고 3은 실행 중에 취소 됩니다. 예외가 throw 되는 WaitAll 에 의해 처리 되며 메서드 호출을 try / catch 블록입니다.

 

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

public class Example
{
   public static void Main()
   {
      // Create a cancellation token and cancel it.
      var source1 = new CancellationTokenSource();
      var token1 = source1.Token;
      source1.Cancel();
      // Create a cancellation token for later cancellation.
      var source2 = new CancellationTokenSource();
      var token2 = source2.Token;
       
      // Create a series of tasks that will complete, be cancelled, 
      // timeout, or throw an exception.
      Task[] tasks = new Task[12];
      for (int i = 0; i < 12; i++)
      {
          switch (i % 4) 
          {
             // Task should run to completion.
             case 0:
                tasks[i] = Task.Run(() => Thread.Sleep(2000));
                break;
             // Task should be set to canceled state.
             case 1:   
                tasks[i] = Task.Run( () => Thread.Sleep(2000),
                         token1);
                break;         
             case 2:
                // Task should throw an exception.
                tasks[i] = Task.Run( () => { throw new NotSupportedException(); } );
                break;
             case 3:
                // Task should examine cancellation token.
                tasks[i] = Task.Run( () => { Thread.Sleep(2000); 
                                             if (token2.IsCancellationRequested)
                                                token2.ThrowIfCancellationRequested();
                                             Thread.Sleep(500); }, token2);   
                break;
          }
      }
      Thread.Sleep(250);
      source2.Cancel();
       
      try {
         Task.WaitAll(tasks);
      }
      catch (AggregateException ae) {
          Console.WriteLine("One or more exceptions occurred:");
          foreach (var ex in ae.InnerExceptions)
             Console.WriteLine("   {0}: {1}", ex.GetType().Name, ex.Message);
       }   

      Console.WriteLine("\nStatus of tasks:");
      foreach (var t in tasks) {
         Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
         if (t.Exception != null) {
            foreach (var ex in t.Exception.InnerExceptions)
               Console.WriteLine("      {0}: {1}", ex.GetType().Name,
                                 ex.Message);
         }
      }
   }
}
// The example displays output like the following:
//   One or more exceptions occurred:
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//   
//   Status of tasks:
//      Task #13: RanToCompletion
//      Task #1: Canceled
//      Task #3: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #8: Canceled
//      Task #14: RanToCompletion
//      Task #4: Canceled
//      Task #6: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #7: Canceled
//      Task #15: RanToCompletion
//      Task #9: Canceled
//      Task #11: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #12: Canceled

작업 기반 비동기 작업에서 예외 처리에 대 한 자세한 내용은 참조 하세요. 예외 처리합니다.

 

* 참고 https://docs.microsoft.com/ko-kr/dotnet/api/system.threading.tasks.task?view=netframework-4.8

반응형

+ Recent posts