• .Net4.0如何实现.NET4.5中的Task.Run及Task.Delay方法


    前言

    .NET4.0下是没有Task.Run及Task.Delay方法的,而.NET4.5已经实现,对于还在使用.NET4.0的同学来说,如何在.NET4.0下实现这两个方法呢?

    在.NET4.0下,有一个泛型类,叫TaskCompletionSource<TReuslt>,它能控制Task的行为,如给Task设置结果、设置异常、设置取消等。

    MSDN是这样描述的(网址):

    表示未绑定到委托的 Task<TResult> 的制造者方,并通过Task属性提供对使用者方的访问。

    它有以下两个常用方法:

    1 public void SetException(Exception exception);

    当执行的任务有异常时,可以使用该方法是设置任务的异常。

    1 public void SetResult(TResult result);

    这是给任务设置一个返回值,如果任务没有返回值,直接设置null即可。

    一、Task.Run(Action action)方法

     该方法实现与Task.Factory.StartNew(Action action)类似,实现代码如下:

     1         public static Task Run(Action action)
     2         {
     3             var tcs = new TaskCompletionSource<object>();
     4             new Thread(() => {
     5                 try
     6                 {
     7                     action();
     8                     tcs.SetResult(null);
     9                 }
    10                 catch (Exception ex)
    11                 {
    12                     tcs.SetException(ex);
    13                 }
    14             }){ IsBackground = true }.Start();
    15             return tcs.Task;
    16         }

    该方法的目的是用来执行委托action所代表的方法,并返回当前所表示的任务,因方法的签名返回值类型为Task,所以需给tcs的SetResult方法设置一个null值。

    测试代码如下:

    1             TaskEx.Run(() =>
    2             {
    3                 Thread.Sleep(5000);
    4                 Console.WriteLine("Just For Test.");
    5             });

    该代码的功能是在5s后输出“Just For Test”字符串到控制台。

    注:TaskEx是用来封装Run静态方法的一个类,以下内容相同。

    二、Task.Run<TResult>(Func<TResult> function)方法

    该方法是Task.Run(Action action)的泛型版本,实现如下:

     1         public static Task<TResult> Run<TResult>(Func<TResult> function)
     2         {
     3             var tcs = new TaskCompletionSource<TResult>();
     4             new Thread(() =>
     5             {
     6                 try
     7                 {
     8                     tcs.SetResult(function());
     9                 }
    10                 catch (Exception ex)
    11                 {
    12                     tcs.SetException(ex);
    13                 }
    14             })
    15             { IsBackground = true }.Start();
    16             return tcs.Task;
    17         }

    与Task.Run的非泛型版本类似,该方法的目的是用来执行委托function所代表的方法,并返回当前所表示的任务,该任务类型为Task<TResut>,带有Task的返回值。

    测试代码如下:

    1             string result = TaskEx.Run(() =>
    2             {
    3                 Thread.Sleep(5000);
    4                 return "Just For Test.";
    5             }).Result;
    6             Console.WriteLine(result);

    该方法的功能与上面的例子一样:在5s后输出“Just For Test”字符串到控制台,但其实现方式不一样,一个用的是Action委托,另外一个使用的是Function<TResult>委托。

    二、Task.Delay(int milliSeconds)方法

    1         public static Task Delay(int milliseconds)
    2         {
    3             var tcs = new TaskCompletionSource<object>();
    4             var timer = new System.Timers.Timer(milliseconds) { AutoReset = false };
    5             timer.Elapsed += delegate { timer.Dispose();tcs.SetResult(null); };
    6             timer.Start();
    7             return tcs.Task;
    8         }

    以上代码功能使用了System.Timers.Timer类来实现任务的延时,用来在milliSeconds毫秒后返回当前任务,该方法并不会阻塞人任何线程。

    测试代码如下:

    1             TaskEx.Delay(5000).Wait();
    2             Console.WriteLine("Just For Test.");

    该方法的功能还是与前面的两个一样,在5s后输出“Just For Test”字符串到控制台。

    完整代码:

     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace ConsoleApp
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             //Task.Run(Action action)方法
    12             TaskEx.Run(() =>
    13             {
    14                 Thread.Sleep(5000);
    15                 Console.WriteLine("Just For Test.");
    16             });
    17 
    18             //Task.Run<TResult>(Func<TResult> function)方法
    19             string result = TaskEx.Run(() =>
    20             {
    21                 Thread.Sleep(5000);
    22                 return "Just For Test.";
    23             }).Result;
    24             Console.WriteLine(result);
    25 
    26             //Task.Delay(int milliSeconds)方法
    27             TaskEx.Delay(5000).Wait();
    28             Console.WriteLine("Just For Test.");
    29             Console.ReadKey();
    30         }
    31     }
    32     class TaskEx
    33     {
    34         public static Task Run(Action action)
    35         {
    36             var tcs = new TaskCompletionSource<object>();
    37             new Thread(() => {
    38                 try
    39                 {
    40                     action();
    41                     tcs.SetResult(null);
    42                 }
    43                 catch (Exception ex)
    44                 {
    45                     tcs.SetException(ex);
    46                 }
    47             }){ IsBackground = true }.Start();
    48             return tcs.Task;
    49         }
    50         public static Task<TResult> Run<TResult>(Func<TResult> function)
    51         {
    52             var tcs = new TaskCompletionSource<TResult>();
    53             new Thread(() =>
    54             {
    55                 try
    56                 {
    57                     tcs.SetResult(function());
    58                 }
    59                 catch (Exception ex)
    60                 {
    61                     tcs.SetException(ex);
    62                 }
    63             })
    64             { IsBackground = true }.Start();
    65             return tcs.Task;
    66         }
    67         public static Task Delay(int milliseconds)
    68         {
    69             var tcs = new TaskCompletionSource<object>();
    70             var timer = new System.Timers.Timer(milliseconds) { AutoReset = false };
    71             timer.Elapsed += delegate { timer.Dispose();tcs.SetResult(null); };
    72             timer.Start();
    73             return tcs.Task;
    74         }
    75     }
    76 }
  • 相关阅读:
    mount命令详解
    traceroute命令详解
    etcd节点扩容至两个节点
    shell历史命令
    etcd单节点安装
    linux中修改环境变量及生效方法
    ansible最佳实战部署nginx
    用roles部署nginx
    playbook部署mangodb
    安装mangodb
  • 原文地址:https://www.cnblogs.com/cncc/p/6231847.html
Copyright © 2020-2023  润新知