zoukankan      html  css  js  c++  java
  • 08、C# Task的使用

    Task

    Task基础

    Task在线程池的基础上进行了优化,并提供了更多的API。在FCL4.0中,如果我们要编写多线程程序,Task显然已经优于传统的方式。

    若要等待单个任务完成,可以调用其 Task.Wait方法。 对方法的调用会 Wait阻止调用线程,直到单类实例执行完毕。

    以下是一个简单的任务示例:

    class Program {
        static void Main(string[] args) {
            Task task = new Task((() => {
                Thread.Sleep(3000);
            }));
            task.Start();
            task.ContinueWith((task1 => {
                Console.WriteLine("任务完成");
                Console.WriteLine("IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task1.IsCanceled, task1.IsCompleted, task1.IsFaulted);
            }));
            Console.ReadKey();
        }
    }
    

    ContinueWith是任务的串行,当任务完成后会执行ContinueWith中的代码。

    Task的创建

    Task的创建有很多种方式,主要分为带返回值和不带返回值的方式,这里会详细讲述。

    不带返回值的方式

    第一种创建方式

    class Program {
        static void Main(string[] args) {
            Task task = new Task((() => {
                Thread.Sleep(3000);
                Console.WriteLine("Task Run Finish");
            }));
            task.Start();
            task.Wait(); // 或者Task.WaitAll(task);
            task.Dispose();
            Console.ReadKey();
        }
    }
    

    其中task.Wait()是等待当前Task执行完毕,而Task.WaitAll(...)可以用于等待所有任务执行完毕。

    除此之外,构造函数还提供另外一种创建方式:

    public Task (Action<object?> action, object? state);
    

    其中action是要异步执行的操作委托,而state包含由 action 委托使用的数据的对象。

    第二种创建方式

    class Program {
        static void Main(string[] args) {
            Task task = Task.Run((() => {
                Thread.Sleep(3000);
                Console.WriteLine("Task Run Finish");
            }));
            Console.ReadKey();
        }
    }
    

    第三种创建方式

    class Program {
        static void Main(string[] args) {
            Task task = Task.Factory.StartNew((() => {
                Thread.Sleep(3000);
                Console.WriteLine("Task Run Finish");
            }));
            Console.ReadKey();
        }
    }
    

    还可以将任务标记为长时间运行任务,此时任务不会使用线程池,而是在单独线程中运行。

    class Program {
        static void Main(string[] args) {
            Task task = Task.Factory.StartNew(() => Thread.Sleep(3000), TaskCreationOptions.LongRunning);
            Console.ReadKey();
        }
    }
    

    在上述代码中,创建Task的格式如下所示:

    public System.Threading.Tasks.Task StartNew (Action<object?> action, object? state);
    

    其中action是要异步执行的操作委托,而state包含由 action 委托使用的数据的对象。

    第四种创建方式

    创建Task还可以使用async/await的方式来实现。

    class Program {
        static void Main(string[] args) {
            AsyncFunction();
            Console.ReadKey();
        }
    
        async static void AsyncFunction() {
            await Task.Delay(3000);
            Console.WriteLine("Task Run Finish");
        }
    }
    

    带返回值的方式

    第一种创建方式

    class Program {
        static void Main(string[] args) {
            Task<int> task = new Task<int>((() => {
                Thread.Sleep(3000);
                Console.WriteLine("Task Run Finish");
                return 0;
            }));
            task.Start();
            int resulr = task.Result;
            Console.WriteLine("Task Result:" + resulr);
            Console.ReadKey();
        }
    }
    

    第二种创建方式

    class Program {
        static void Main(string[] args) {
            Task<int> task = Task.Run((() => {
                Thread.Sleep(3000);
                Console.WriteLine("Task Run Finish");
                return 0;
            }));
            int resulr = task.Result;
            Console.WriteLine("Task Result:" + resulr);
            Console.ReadKey();
        }
    }
    

    第三种创建方式

    class Program {
        static void Main(string[] args) {
            Task<int> task = Task.Factory.StartNew((() => {
                Thread.Sleep(3000);
                Console.WriteLine("Task Run Finish");
                return 0;
            }));
            Console.ReadKey();
        }
    }
    

    第四种创建方式

    创建Task还可以使用async/await的方式来实现。

    class Program {
        static void Main(string[] args) {
            Task<int> task = GetAsyncResult();
            int result = task.Result;  // 阻塞主线程
            task.Dispose();
            Console.WriteLine("结果是:" + result);
        }
    
        private async static Task<int> GetAsyncResult() {
            await Task.Delay(3000);
            Console.WriteLine("Task Run Finish");
            return 0;
        }
    }
    

    使用task.Result方式同步获取结果会阻塞主线程。如果想要返回异步的结果,则使用如下方式:

    private static Task<int> GetAsyncResult() {
        Console.WriteLine("Task Run Finish");
        return Task.FromResult(0);
    }
    

    组合任务-ContinueWith

    任务并行

    下面是一个简单的实例,task1开启子线程执行异步操作,主线程处理其他的操作。

    class Program {
        static void Main(string[] args) {
            Task<int> task1 = new Task<int>((() => {
                Console.WriteLine("使用Task执行异步操作.");
                int sum = 0;
                for (int i = 0; i < 100; i++) {
                    sum += i;
                }
                return sum;
            }));
            task1.Start();
            Console.WriteLine("主线程执行其他操作");
            Task task2 = task1.ContinueWith((task => {
                Console.WriteLine("任务完成后的执行结果{0}", task.Result.ToString());
            }));
            task1.Wait();
            task2.Wait();
        }
    }
    

    输出结果如下:

    主线程执行其他操作
    使用Task执行异步操作.
    任务完成后的执行结果4950

    任务串行

    创建四个任务,task1串行执行,task2和task3并行执行完毕后,task4串行执行。

    class Program {
        static void Main(string[] args) {
            // Task1串行执行
            Task task1 = Task.Factory.StartNew((() => {
                Console.WriteLine("task1 Execute");
            }));
            // task2 和 task3并行执行
            Task task2 = task1.ContinueWith((task => {
                Console.WriteLine("task2 Execute");
            }));
            Task task3 = task1.ContinueWith((task => {
                Console.WriteLine("task3 Execute");
            }));
            Task.WaitAll(task2, task3);
            // task4 串行执行
            Task task4 = Task.Factory.StartNew((() => {
                Console.WriteLine("task4 Execute");
            }));
            task4.Wait();
        }
    }
    

    输出结果如下:

    task1 Execute
    task3 Execute
    task2 Execute
    task4 Execute

    父子任务

    在父子任务中,TaskCreationOptions指定用于控制任务的创建和执行的可选行为的标志。

    AttachedToParent:指定将任务附加到任务层次结构中的某个父级。
    DenyChildAttach:指定任何尝试作为附加的子任务执行(即,使用AttachedToParent选项创建)的子任务都无法附加到父任务,会改成作为分离的子任务执行。
    HideScheduler:防止环境计划程序被视为已创建任务的当前计划程序。
    LongRunning:指定任务将是长时间运行的,粗粒度的操作,涉及比细化的系统更少、更强大的组件。
    None:指定应使用默认行为。
    PreferFairness:提示TaskScheduler以一种尽可能公平的方式安排任务
    RunContinuationsAsynchronously:强制异步执行添加到当前任务的延续任务。

    简单的代码演示如下:

    class Program {
        static void Main(string[] args) {
            Task<int> parentTask = new Task<int>(state => {
                Console.WriteLine(state);
                // 创建并启动子任务
                new Task((() => {
                    Console.WriteLine("task1 Execute");
                }), TaskCreationOptions.AttachedToParent).Start();
                new Task((() => {
                    Console.WriteLine("task2 Execute");
                }), TaskCreationOptions.AttachedToParent).Start();
                return 0;
            }, "父任务,所有子任务完成后才执行");
            // 任务完成后执行的操作
            parentTask.ContinueWith((task => {
                Console.WriteLine("Parent Task Finish");
            }));
            parentTask.Start();
            Console.ReadKey();
        }
    }
    

    输出结果如下:

    父任务,所有子任务完成后才执行
    task1 Execute
    task2 Execute
    Parent Task Finish

    取消任务

    class Program {
        static void Main(string[] args) {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            Task task = new Task((() => {
                for (int i = 0; i < 100; i++) {
                    Thread.Sleep(1000);
                    Console.WriteLine("Task Execute{0}", i);
                }
            }), cancellationTokenSource.Token);
            task.Start();
            // 取消任务的运行
            cancellationTokenSource.Cancel();
            Console.ReadKey();
        }
    }
    

    任务进度

    使用IProgress实现异步编程的进程通知。

    class Program {
        static void Main(string[] args) {
            Task task = displayProgress();
            task.Wait();
        }
    
        private static async Task displayProgress() {
            Progress<int> progress = new Progress<int>(percent => {
                Console.WriteLine("{0}%", percent);
            });
            await Task.Run((() => DoProcessing(progress)));
            Console.WriteLine("Finish");
        }
    
        private static void DoProcessing(IProgress<int> progress) {
            for (int i = 0; i < 100; i++) {
                Thread.Sleep(100);
                progress.Report(i);
            }
        }
    }
    

    输出结果:

    0%
    1%
    2%
    3%
    ......
    Finish

  • 相关阅读:
    java中调用kettle转换文件
    开源游戏引擎体验
    cocos2d-x 托付模式的巧妙运用——附源代码(二)
    BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 第9章节--client对象模型和REST APIs概览 Windows Phone
    redis String结构
    Redis 键命令
    Redis 基础命令
    linux curl 命令的使用
    将spring boot项目部署到tomcat容器中
    Redis常用命令
  • 原文地址:https://www.cnblogs.com/pengjingya/p/14593143.html
Copyright © 2011-2022 走看看