C# Tasks

互联网 2021/4/8 12:12:57

Compared to a thread, a Task is higher-level abstraction—it represents a concurrent operation that might or might not be backed by a thread. Tasks are compositional (you can chain them together through the use of continuations). They can use the thre…

Compared to a thread, a Task is higher-level abstraction—it represents a concurrent operation that might or might not be backed by a thread. Tasks are compositional (you can chain them together through the use of continuations). They can use the thread pool to lessen startup latency, and with a TaskCompletionSource, they can employ a callback approach that avoids threads altogether while waiting on I/O-bound operations.

Starting a Task

The easiest way to start a Task backed by a thread is with the static method Task.Run (the Task class is in the System.Threading.Tasks namespace). Simply pass in an Action delegate:

Task.Run (() => Console.WriteLine ("Foo"));

Tasks use pooled threads by default, which are background threads. This means that when the main thread ends, so do any tasks that you create.

Calling Task.Run in this manner is similar to starting a thread as follows (except for the thread pooling implications that we discuss shortly):

new Thread (() => Console.WriteLine ("Foo")).Start();

Task.Run returns a Task object that we can use to monitor its progress, rather like a Thread object.You can track a task’s execution status via its Status property.

WAIT

Calling Wait on a task blocks until it completes and is the equivalent of calling Join on a thread:

Task task = Task.Run (() =>
{
  Thread.Sleep (2000);
  Console.WriteLine ("Foo");
});
Console.WriteLine (task.IsCompleted);  // False
task.Wait();  // Blocks until task is complete

Returning values

Task has a generic subclass called Task< TResult >, which allows a task to emit a return value. You can obtain a Task< TResult > by calling Task.Run with a Func< TResult > delegate (or a compatible lambda expression) instead of an Action:

Task<int> task = Task.Run (() => { Console.WriteLine ("Foo"); return 3; });
// ...

You can obtain the result later by querying the Result property. If the task hasn’t yet finished, accessing this property will block the current thread until the task finishes:

int result = task.Result;      // Blocks if not already finished
Console.WriteLine (result);    // 3

In the following example, we create a task that uses LINQ to count the number of prime numbers in the first three million (+2) integers:

Task<int> primeNumberTask = Task.Run (() =>
  Enumerable.Range (2, 3000000).Count (n => 
    Enumerable.Range (2, (int)Math.Sqrt(n)-1).All (i => n % i > 0)));

Console.WriteLine ("Task running...");
Console.WriteLine ("The answer is " + primeNumberTask.Result);

Task< TResult > can be thought of as a “future,” in that it encapsulates a Result that becomes available later in time.

Exceptions

Unlike with threads, tasks conveniently propagate exceptions. So, if the code in your task throws an unhandled exception (in other words, if your task faults), that exception is automatically rethrown to whoever calls Wait()—or accesses the Result property of a Task< TResult >:

// Start a Task that throws a NullReferenceException:
Task task = Task.Run (() => { throw null; });
try 
{
  task.Wait();
}
catch (AggregateException aex)
{
  if (aex.InnerException is NullReferenceException)
    Console.WriteLine ("Null!");
  else
    throw;
}

Continuations

A continuation says to a task, “when you’ve finished, continue by doing something else.” A continuation is usually implemented by a callback that executes once upon completion of an operation. There are two ways to attach a continuation to a task. The first is particularly significant because it’s used by C#’s asynchronous functions, as you’ll see soon. We can demonstrate it with the prime number counting task that we wrote a short while ago in “Returning values”:

Task<int> primeNumberTask = Task.Run (() =>
  Enumerable.Range (2, 3000000).Count (n => 
    Enumerable.Range (2, (int)Math.Sqrt(n)-1).All (i => n % i > 0)));

var awaiter = primeNumberTask.GetAwaiter();
awaiter.OnCompleted (() => 
{
  int result = awaiter.GetResult();
  Console.WriteLine (result);       // Writes result
});
随时随地学软件编程-关注百度小程序和微信小程序
关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[C# Tasks]http://www.zyiz.net/tech/detail-153783.html

上一篇:75亿美元!微软正式收购GitHub!

下一篇:【原创】C#初级教程学习笔记003-变量和表达式

赞(0)

共有 条评论 网友评论

验证码: 看不清楚?
    关注微信小程序
    程序员编程王-随时随地学编程

    扫描二维码或查找【程序员编程王】

    可以随时随地学编程啦!

    技术文章导航 更多>
    扫一扫关注最新编程教程