- Task Class
- Task<TResult> Class
- TaskFactory Class
- TaskFactory<TResult> Class
Task Class
https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx
Represents an asynchronous operation.
To browse the .NET Framework source code for this type, see the Reference Source.
Namespace: System.Threading.Tasks
Assembly: mscorlib (in mscorlib.dll)
Remarks
![]() |
---|
To view the .NET Framework source code for this type, see the Reference Source. You can browse through the source code online, download the reference for offline viewing, and step through the sources (including patches and updates) during debugging; see instructions. |
The Task class represents a single operation that does not return a value and that usually executes asynchronously. Task objects are one of the central components of the task-based asynchronous pattern first introduced in the .NET Framework 4. Because the work performed by a Task object typically executes asynchronously on a thread pool thread rather than synchronously on the main application thread, you can use the Status property, as well as the IsCanceled, IsCompleted, and IsFaulted properties, to determine the state of a task. Most commonly, a lambda expression is used to specify the work that the task is to perform.
For operations that return values, you use the Task<TResult> class.
In this section:
Creating and executing a task
Separating task creation and execution
Waiting for one or more tasks to complete
Tasks and culture
For debugger developers
Creating and executing a task
Task instances may be created in a variety of ways. The most common approach, which is available starting with the .NET Framework 4.5, is to call the static Run method. The Run method provides a simple way to start a task using default values and without requiring additional parameters. The following example uses the Run(Action) method to start a task that loops and then displays the number of loop iterations:
using System; using System.Threading.Tasks; public class Example { public static void Main() { Task t = Task.Run( () => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) {} Console.WriteLine("Finished {0} loop iterations", ctr); } ); t.Wait(); } } // The example displays the following output: // Finished 1000001 loop iterations
An alternative, and the most common method to start a task in .NET Framework 4, is the static TaskFactory.StartNew method. The Task.Factory property returns a TaskFactory object. Overloads of the TaskFactory.StartNew method let you specify parameters to pass to the task creation options and a task scheduler. The following example uses the TaskFactory.StartNew method to start a task. It is functionally equivalent to the code in the previous example.
using System; using System.Threading.Tasks; public class Example { public static void Main() { Task t = Task.Factory.StartNew( () => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) {} Console.WriteLine("Finished {0} loop iterations", ctr); } ); t.Wait(); } } // The example displays the following output: // Finished 1000001 loop iterations
For more complete examples, see Task-based Asynchronous Programming.
Separating task creation and execution
The Task class also provides constructors that initialize the task but that do not schedule it for execution. For performance reasons, the Task.Run or TaskFactory.StartNew method is the preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation and scheduling must be separated, you can use the constructors and then call the Task.Start method to schedule the task for execution at a later time.
Waiting for one or more tasks to complete
Because tasks typically run asynchronously on a thread pool thread, the thread that creates and starts the task continues execution as soon as the task has been instantiated. In some cases, when the calling thread is the main application thread, the app may terminate before any the task actually begins execution. In others, your application's logic may require that the calling thread continue execution only when one or more tasks has completed execution. You can synchronize the execution of the calling thread and the asynchronous tasks it launches by calling a Wait method to wait for one or more tasks to complete.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution.
The following example calls the parameterless Wait() method to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
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
You can also conditionally wait for a task to complete. The Wait(Int32) and Wait(TimeSpan) methods block the calling thread until the task finishes or a timeout interval elapses, whichever comes first. Since the following example launches a task that sleeps for two seconds but defines a one-second timeout value, the calling thread blocks until the timeout expires and before the task has completed execution.
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.
You can also supply a cancellation token by calling the Wait(CancellationToken) and Wait(Int32, CancellationToken) methods. If the token's IsCancellationRequested property is true, the wait is cancelled; if it becomes true while the Wait method terminates.
In some cases, you may want to wait for the first of a series of executing tasks to complete, but don't care which task it is. For this purpose, you can call one of the overloads of the Task.WaitAll method. The following example creates three tasks, each of which sleeps for an interval determine by a random number generator. The WaitAny(Task[]) method waits for the first task to complete. The example then displays information about the status of all three tasks.
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
You can also wait for all of a series of tasks to complete by calling the WaitAll method. The following example creates ten tasks, waits for all ten to complete, and then displays their status.
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
Note that when you wait for one or more tasks to complete, any exceptions thrown in the running tasks are propagated on the thread that calls the Wait method, as the following example shows. It launches 12 tasks, three of which complete normally and three of which throw an exception. Of the remaining six tasks, three are cancelled before the start, and three are cancelled while they executing. Exceptions are thrown in the WaitAll method call and are handled by a try/catch block.
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
For more information on exception handling in task-based asynchronous operations, see Exception Handling (Task Parallel Library).
Tasks and culture
Starting with desktop apps that target the .NET Framework 4.6, the culture of the thread that creates and invokes a task becomes part of the thread's context. That is, regardless of the current culture of the thread on which the task executes, the current culture of the task is the culture of the calling thread. For apps that target versions of the .NET Framework prior to the .NET Framework 4.6, the culture of the task is the culture of the thread on which the task executes. For more information, see the "Culture and task-based asynchronous operations" section in the CultureInfo topic.
![]() |
---|
Store apps follow the Windows Runtime in setting and getting the default culture. |
For debugger developers
For developers implementing custom debuggers, several internal and private members of task may be useful (these may change from release to release). The m_taskId field serves as the backing store for the Id property, however accessing this field directly from a debugger may be more efficient than accessing the same value through the property's getter method (the s_taskIdCounter counter is used to retrieve the next available ID for a task). Similarly, the m_stateFlags field stores information about the current lifecycle stage of the task, information also accessible through the Status property. The m_action field stores a reference to the task's delegate, and the m_stateObject field stores the async state passed to the task by the developer. Finally, for debuggers that parse stack frames, the InternalWait method serves a potential marker for when a task is entering a wait operation.
Examples
The following example creates and executes four tasks. Three tasks execute an Action<T> delegate named action, which accepts an argument of type Object. A fourth task executes a lambda expression (an Action delegate) that is defined inline in the call to the task creation method. Each task is instantiated and run in a different way:
Task t1 is instantiated by calling a Task class constructor, but is started by calling its Start() method only after task t2 has started.
Task t2 is instantiated and started in a single method call by calling the TaskFactory.StartNew(Action<Object>, Object) method.
Task t3 is instantiated and started in a single method call by calling the Run(Action) method.
Task t4 is executed synchronously on the main thread by calling the RunSynchronously() method.
Because task t4 executes synchronously, it executes on the main application thread. The remaining tasks execute asynchronously typically on one or more thread pool threads.
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 demonstate 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<TResult> Class
https://msdn.microsoft.com/en-us/library/dd321424.aspx
Represents an asynchronous operation that can return a value.
Namespace: System.Threading.Tasks
Assembly: mscorlib (in mscorlib.dll)
Remarks
The Task<TResult> class represents a single operation that returns a value and that usually executes asynchronously. Task<TResult> objects are one of the central components of the first introduced in the .NET Framework 4. Because the work performed by a Task<TResult> object typically executes asynchronously on a thread pool thread rather than synchronously on the main application thread, you can use the Status property, as well as the IsCanceled, IsCompleted, and IsFaulted properties, to determine the state of a task. Most commonly, a lambda expression is used to specify the work that the task is to perform.
Task<TResult> instances may be created in a variety of ways. The most common approach, which is available starting with the .NET Framework 4.5, is to call the static Task.Run<TResult>(Func<TResult>) or Task.Run<TResult>(Func<TResult>, CancellationToken) method. These methods provide a simple way to start a task by using default values and without acquiring additional parameters. The following example uses the Task.Run<TResult>(Func<TResult>) method to start a task that loops and then displays the number of loop iterations:
using System; using System.Threading.Tasks; public class Example { public static void Main() { var t = Task<int>.Run( () => { // Just loop. int max = 1000000; int ctr = 0; for (ctr = 0; ctr <= max; ctr++) { if (ctr == max / 2 && DateTime.Now.Hour <= 12) { ctr++; break; } } return ctr; } ); Console.WriteLine("Finished {0:N0} iterations.", t.Result); } } // The example displays output like the following: // Finished 1,000,001 loop iterations.
An alternative, and the most common way to start a task in the .NET Framework 4, is to call the static TaskFactory.StartNew or TaskFactory<TResult>.StartNew method. The Task.Factory property returns a TaskFactory object, and the Task<TResult>.Factory property returns a TaskFactory<TResult> object. Overloads of their StartNew method let you pass arguments, define task creation options, and specify a task scheduler. The following example uses the TaskFactory<TResult>.StartNew(Func<TResult>) method to start a task. It is functionally equivalent to the code in the previous example.
using System; using System.Threading.Tasks; public class Example { public static void Main() { var t = Task<int>.Factory.StartNew( () => { // Just loop. int max = 1000000; int ctr = 0; for (ctr = 0; ctr <= max; ctr++) { if (ctr == max / 2 && DateTime.Now.Hour <= 12) { ctr++; break; } } return ctr; } ); Console.WriteLine("Finished {0:N0} iterations.", t.Result); } } // The example displays the following output: // Finished 1000001 loop iterations
For more complete examples, see Task-based Asynchronous Programming.
The Task<TResult> class also provides constructors that initialize the task but that do not schedule it for execution. For performance reasons, the Task.Run and StartNew methods are the preferred mechanism for creating and scheduling computational tasks, but for scenarios where task creation and scheduling must be separated, the constructors may be used, and the task's Start method may then be used to schedule the task for execution at a later time.
Starting with desktop apps that target the .NET Framework 4.6, the culture of the thread that creates and invokes a task becomes part of the thread's context. That is, regardless of the current culture of the thread on which the task executes, the current culture of the task is the culture of the calling thread. For apps that target versions of the .NET Framework prior to the .NET Framework 4.6, the culture of the task is the culture of the thread on which the task executes. For more information, see the "Culture and task-based asynchronous operations" section in the CultureInfo topic. Note that Store apps follow the Windows Runtime in setting and getting the default culture.
For operations that do not return a value, you use the Task class.
TaskFactory Class
https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory(v=vs.110).aspx
Provides support for creating and scheduling Task objects.
Namespace: System.Threading.Tasks
Assembly: mscorlib (in mscorlib.dll)
Inheritance Hierarchy
Remarks
The .NET Framework provides two factories for creating and scheduling tasks:
The TaskFactory class, which creates Task and Task<TResult> objects. You can call the overloads of this method to create and execute a task that requires non-default arguments.
Warning
Starting with the .NET Framework 4.5, the Task.Run method provides the easiest way to create a task with default configuration values and start it immediately.
The TaskFactory<TResult> class, which creates Task<TResult> objects.
The TaskFactory class allows you to do the following:
Create a task and start it immediately by calling the StartNew method.
Warning
Starting with the .NET Framework 4.5, the Task.Run method provides the easiest way to create a task with default configuration values and start it immediately.
Create a task that starts when any one of the tasks in an array has completed by calling the ContinueWhenAny method.
Create a task that starts when all the tasks in an array have completed by calling the ContinueWhenAll method.
The static Task<TResult>.Factory property returns a default TaskFactory<TResult> object. You can also call one of the TaskFactory class constructors to configure the Task objects that the TaskFactory class creates. The following example configures a new TaskFactory object to create tasks that have a specified cancellation token, task creation options, continuation options, and a customized task scheduler.
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; class Example { static CancellationTokenSource cts = new CancellationTokenSource(); static TaskFactory factory = new TaskFactory( cts.Token, TaskCreationOptions.PreferFairness, TaskContinuationOptions.ExecuteSynchronously, new CustomScheduler()); static void Main() { var t2 = factory.StartNew(() => DoWork()); cts.Dispose(); } static void DoWork() {/*...*/ } }
In most cases, you do not have to instantiate a new TaskFactory instance. Instead, you can use the Task.Factory property, which returns a factory object that uses default values. You can then call its methods to start new tasks or define task continuations. For an illustration, see the example.
Examples
The following example uses the static Factory property to make two calls to the TaskFactory.StartNew method. The first populates an array with the names of files in the user's MyDocuments directory, while the second populates an array with the names of subdirectories of the user's MyDocuments directory. It then calls the TaskFactory.ContinueWhenAll(Task[], Action<Task[]>) method, which displays information about the number of files and directories in the two arrays after the first two tasks have completed execution.
using System; using System.IO; using System.Threading.Tasks; public class Example { public static void Main() { Task[] tasks = new Task[2]; String[] files = null; String[] dirs = null; String docsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); tasks[0] = Task.Factory.StartNew( () => files = Directory.GetFiles(docsDirectory)); tasks[1] = Task.Factory.StartNew( () => dirs = Directory.GetDirectories(docsDirectory)); Task.Factory.ContinueWhenAll(tasks, completedTasks => { Console.WriteLine("{0} contains: ", docsDirectory); Console.WriteLine(" {0} subdirectories", dirs.Length); Console.WriteLine(" {0} files", files.Length); } ); } } // The example displays output like the following: // C:\Users\<username>\Documents contains: // 24 subdirectories // 16 files
TaskFactory<TResult> Class
https://msdn.microsoft.com/en-us/library/dd321260(v=vs.110).aspx
Provides support for creating and scheduling Task<TResult> objects.
Namespace: System.Threading.Tasks
Assembly: mscorlib (in mscorlib.dll)
Remarks
The .NET Framework provides two factories for creating and scheduling tasks:
The TaskFactory class, which creates Task and Task<TResult> objects.
The TaskFactory<TResult> class, which creates Task<TResult> objects.
The TaskFactory<TResult> class allows you to do the following:
Create a task and start it immediately by calling the StartNew method. You can call the overloads of this method to create and execute a task that requires non-default arguments.
Warning
Starting with the .NET Framework 4.5, the Task.Run method provides the easiest way to create a task with default configuration values and start it immediately.
Create a task that starts when any one of the tasks in an array has completed by calling the ContinueWhenAny orContinueWhenAny<TResult> method.
Create a task that starts when all the tasks in an array have completed by calling the ContinueWhenAll or ContinueWhenAll<TResult> method.
The static Task<TResult>.Factory property returns a default TaskFactory<TResult> object. You can also call one of the TaskFactory<TResult> class constructors to configure the Task<TResult> objects that the TaskFactory<TResult> class creates. The following example configures a new TaskFactory<TResult> object to create tasks that have a specified cancellation token, task creation options, continuation options, and a customized task scheduler.
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; public class Example { static CancellationTokenSource cts = new CancellationTokenSource(); static TaskFactory<int> factory = new TaskFactory<int>( cts.Token, TaskCreationOptions.PreferFairness, TaskContinuationOptions.ExecuteSynchronously, new CustomScheduler()); static void Main() { var t2 = factory.StartNew(() => DoWork()); cts.Dispose(); } static int DoWork() { /*...*/ return DateTime.Now.Hour <= 12 ? 1 : 2; } }
In most cases, you do not have to instantiate a new TaskFactory<TResult> instance. Instead, you can use the static Task<TResult>.Factory property, which returns a factory object that uses default values. You can then call its methods to start new tasks or define task continuations. For an illustration, see the example.
Examples
The following example uses the static Factory property to make two calls to the TaskFactory<TResult>.StartNew method. The first task returns a string array that is populated with the names of files in the user's MyDocuments directory, while the second returns a string array that is populated with the names of subdirectories of the user's MyDocuments directory. It then calls the TaskFactory.ContinueWhenAll(Task[], Action<Task[]>) method, which displays information about the number of files and directories in the arrays returned by the two tasks after they have completed execution.
using System; using System.IO; using System.Threading.Tasks; public class Example { public static void Main() { Task<string[]>[] tasks = new Task<string[]>[2]; String docsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); tasks[0] = Task<string[]>.Factory.StartNew( () => Directory.GetFiles(docsDirectory)); tasks[1] = Task<string[]>.Factory.StartNew( () => Directory.GetDirectories(docsDirectory)); Task.Factory.ContinueWhenAll(tasks, completedTasks => { Console.WriteLine("{0} contains: ", docsDirectory); Console.WriteLine(" {0} subdirectories", tasks[1].Result.Length); Console.WriteLine(" {0} files", tasks[0].Result.Length); } ); } } // The example displays output like the following: // C:\Users\<username>\Documents contains: // 24 subdirectories // 16 files
'프로그래밍 > C#' 카테고리의 다른 글
.NET Framework Regular Expressions (0) | 2017.05.08 |
---|---|
Data Parallelism (Task Parallel Library) (0) | 2017.05.06 |
Task-based Asynchronous Programming (0) | 2017.04.22 |
Asynchronous Programming with async and await (C#) (0) | 2017.04.19 |
Developing Windows Service Applications (0) | 2017.04.02 |