zoukankan      html  css  js  c++  java
  • 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)

    Task - 基于线程池的任务(在 System.Threading.Tasks 命名空间下)

    • 多 Task 的并行执行
    • Parallel - 并行计算(在 System.Threading.Tasks 命名空间下)



    示例
    1、演示 Task(基于线程池的任务)的基本应用
    Thread/Tasks/TaskDemo.xaml

    复制代码
    <Page
        x:Class="XamlDemo.Thread.Tasks.TaskDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Thread.Tasks"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg" FontSize="14.667" />
    
                <Button Name="btnCreateTask" Content="执行一个没有返回值的任务" Click="btnCreateTask_Click_1" Margin="0 10 0 0" />
                <Button Name="btnCancelTask" Content="取消“执行一个没有返回值的任务”" Click="btnCancelTask_Click_1" Margin="0 10 0 0" />
                
                <Button Name="btnCreateTaskWithReturn" Content="执行一个带返回值的任务" Click="btnCreateTaskWithReturn_Click_1" Margin="0 30 0 0" />
                <Button Name="btnCancelTaskWithReturn" Content="取消“执行一个带返回值的任务”" Click="btnCancelTaskWithReturn_Click_1" Margin="0 10 0 0" />
    
            </StackPanel>
        </Grid>
    </Page>
    复制代码

    Thread/Tasks/TaskDemo.xaml.cs

    复制代码
    /*
     * Task - 基于线程池的任务(在 System.Threading.Tasks 命名空间下)
     */
    
    using System;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using System.Threading.Tasks;
    using System.Threading;
    using Windows.UI.Core;
    
    namespace XamlDemo.Thread.Tasks
    {
        public sealed partial class TaskDemo : Page
        {
            /*
             * CancellationTokenSource - 用于取消 CancellationToken 
             *     Token - 一个 CancellationToken 类型的对象,用于关联 Task
             *     IsCancellationRequested - 是否收到了取消操作的请求
             *     Cancel() - 发出取消操作的请求
             *     
             * CancellationToken - 用于关联 Task,以便取消 Task
             *     IsCancellationRequested - 是否收到了取消操作的请求
             *     WaitHandle - 信号,可以通过 WaitHandle.WaitOne() 在当前线程等待
             *     ThrowIfCancellationRequested() - 如果收到了取消操作的请求,则抛出一个 OperationCanceledException 异常
             */
            private CancellationTokenSource _cts;
    
            public TaskDemo()
            {
                this.InitializeComponent();
            }
    
            private void btnCreateTask_Click_1(object sender, RoutedEventArgs e)
            {
                _cts = new CancellationTokenSource();
    
                // 实例化一个 Task,可随时通过 task.Status 获取任务状态
                Task task = new Task(
                    (ctx) => // 任务所调用的方法,没有返回值
                    {
                        // 在当前线程上阻塞 3000 毫秒(当收到取消请求时会发出信号,停止阻塞)
                        _cts.Token.WaitHandle.WaitOne(3000);
    
                        // 收到取消操作的请求后抛出一个 OperationCanceledException 异常,其会导致 task.IsCanceled 的值变为 true
                        // 此处的代码等同于 _cts.Token.ThrowIfCancellationRequested();
                        if (_cts.IsCancellationRequested)
                            throw new OperationCanceledException(_cts.Token);
                    },
                    null, // 上下文对象,task.AsyncState 可获取到此对象,上面的 ctx 也可获取到此对象
                    _cts.Token // 关联的 CancellationToken 对象,用于取消操作
                );
    
                // 开始执行任务
                task.Start();
                // task.Wait(); 在当前线程上等待任务执行完
                lblMsg.Text = "执行了一个没有返回值的任务,3 秒后执行完毕";
    
                // 任务执行完毕后的处理(注:ContinueWith 方法支持任意次回调,即可以写多个 task.ContinueWith() 都会被回调)
                task.ContinueWith(
                    (ctx) => // 任务执行完毕后所调用的方法
                    {
                        if (ctx.IsCanceled) // 任务被取消
                        {
                            var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    lblMsg.Text += "取消了“执行一个没有返回值的任务”";
                                });
                        }
                        if (ctx.IsFaulted) // 任务发生了一个未处理异常
                        {
                            var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    lblMsg.Text += "“执行一个没有返回值的任务”发生了一个未处理异常";
                                });
                        }
                        if (ctx.IsCompleted) // 任务已完成(任务成功地执行完毕或被取消或发生了未处理异常都会 ctx.IsCompleted == true)
                        {
                            var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    lblMsg.Text += "“执行一个没有返回值的任务”执行完成,taskId: " + ctx.Id.ToString();
                                });
                        }
                    });
            }
    
            private void btnCancelTask_Click_1(object sender, RoutedEventArgs e)
            {
                // 发出取消操作的请求
                _cts.Cancel();
                // _cts.CancelAfter(1000); // 1000 毫秒后发出取消操作的请求
            }
    
    
    
            private void btnCreateTaskWithReturn_Click_1(object sender, RoutedEventArgs e)
            {
                _cts = new CancellationTokenSource();
    
                Func<object, string> handler = delegate(object state) // state 是传递过来的上下文对象
                {
                    // 在当前线程上阻塞 3000 毫秒(当收到取消请求时会发出信号,停止阻塞)
                    _cts.Token.WaitHandle.WaitOne(3000);
    
                    // 收到取消操作的请求后抛出一个 OperationCanceledException 异常,其会导致 task.IsCanceled 的值变为 true
                    // 此处的代码等同于 _cts.Token.ThrowIfCancellationRequested();
                    if (_cts.IsCancellationRequested)
                        throw new OperationCanceledException(_cts.Token);
    
                    return "我是“执行一个带返回值的任务”的返回值";
                };
    
                // Task.Factory.StartNew() - 创建任务并马上执行,可随时通过 task.Status 获取任务状态
                // Task.Run() 同样是创建任务并马上执行
                Task<string> task = Task.Factory.StartNew<string>(
                    handler, // 任务所调用的方法,带返回值
                    null, // 上下文对象,task.AsyncState 可获取到此对象
                    _cts.Token // 关联的 CancellationToken 对象,用于取消操作
                );
                lblMsg.Text = "执行了一个带返回值的任务,3 秒后执行完毕";
    
                // 任务执行完毕后的处理(注:ContinueWith 方法支持任意次回调,即可以写多个 task.ContinueWith() 都会被回调)
                task.ContinueWith(
                    (ctx) =>
                    {
                        if (ctx.IsCanceled) // 任务被取消
                        {
                            var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    lblMsg.Text += "取消了“执行一个带返回值的任务”";
                                });
                        }
                        if (ctx.IsFaulted) // 任务发生了一个未处理异常
                        {
                            var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    lblMsg.Text += "“执行一个带返回值的任务”发生了一个未处理异常";
                                });
                        }
                        if (ctx.IsCompleted) // 任务已完成(任务成功地执行完毕或被取消或发生了未处理异常都会 ctx.IsCompleted == true)
                        {
                            var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    lblMsg.Text += "“执行一个带返回值的任务”执行完成,taskId: " + ctx.Id.ToString();
                                });
    
                            // 当任务成功地执行完毕时,输出任务的返回值
                            if (!ctx.IsCanceled && !ctx.IsFaulted)
                            {
                                ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg.Text += Environment.NewLine;
                                    // 任务的返回值
                                    lblMsg.Text += ctx.Result;
                                });
                            }
                        }
                    });
            }
    
            private void btnCancelTaskWithReturn_Click_1(object sender, RoutedEventArgs e)
            {
                // 发出取消操作的请求
                _cts.Cancel();
                // _cts.CancelAfter(1000); // 1000 毫秒后发出取消操作的请求
            }
        }
    }
    复制代码


    2、演示多 Task 的并行执行
    Thread/Tasks/MultiTask.xaml

    复制代码
    <Page
        x:Class="XamlDemo.Thread.Tasks.MultiTask"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Thread.Tasks"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg" FontSize="14.667" />
    
                <Button Name="btnCreateMultiTask" Content="任务并行执行" Click="btnCreateMultiTask_Click_1" Margin="0 10 0 0" />
    
            </StackPanel>
        </Grid>
    </Page>
    复制代码

    Thread/Tasks/MultiTask.xaml.cs

    复制代码
    /*
     * 演示多 Task 的并行执行
     * 
     * 注:
     * 本例中同时创建了三个任务 task1, task2, task3,但是由于 Task 是基于线程池的,所以三个任务的启动时间是不一样的,启动顺序是不一定的
     * 启动顺序可能是 task1->task2->task3,也可能是 task3->task2->task1,也可能是 task2->task3->task1,等等等等都有可能,是不一定的
     */
    
    using System;
    using System.Threading.Tasks;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace XamlDemo.Thread.Tasks
    {
        public sealed partial class MultiTask : Page
        {
            private static int _count = 0;
    
            public MultiTask()
            {
                this.InitializeComponent();
            }
    
            private void btnCreateMultiTask_Click_1(object sender, RoutedEventArgs e)
            {
                // 创建并执行任务1
                Task task1 = Task.Run(
                    () =>
                    {
                        new System.Threading.ManualResetEvent(false).WaitOne(3000);
                        System.Threading.Interlocked.Increment(ref _count);
                    });
                // 创建并执行任务2
                Task task2 = Task.Run(
                    () =>
                    {
                        new System.Threading.ManualResetEvent(false).WaitOne(3000);
                        System.Threading.Interlocked.Increment(ref _count);
                    });
                // 创建并执行任务3
                Task task3 = Task.Run(
                   () =>
                   {
                       new System.Threading.ManualResetEvent(false).WaitOne(3000);
                       System.Threading.Interlocked.Increment(ref _count);
                   });
    
                // 将所有任务合成一个 Task 对象,不会阻塞 UI 线程,通过 task.ContinueWith() 获取结果
                Task task = Task.WhenAll(task1, task2, task3);
                // Task.WaitAll(task1, task2, task3); 等待所有任务完成,会阻塞 UI 线程
    
                DateTime dt = DateTime.Now;
    
                // task 执行完毕后的处理,即所有任务执行完毕后的处理
                task.ContinueWith(
                    (ctx) =>
                    {
                        var ignored = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
                            () =>
                            {
                                lblMsg.Text = "count: " + _count.ToString() + ", 执行时间: " + (DateTime.Now - dt).TotalSeconds.ToString() + "秒";
                            });
                    });
            }
        }
    }
    复制代码


    3、演示 Parallel(并行计算)的基本应用
    Thread/Tasks/ParallelDemo.xaml

    复制代码
    <Page
        x:Class="XamlDemo.Thread.Tasks.ParallelDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Thread.Tasks"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg1" FontSize="14.667" />
                <TextBlock Name="lblMsg2" FontSize="14.667" />
    
                <Button Name="btnCreateParallel" Content="执行一个并行运算(Parallel)" Click="btnCreateParallel_Click_1" Margin="0 10 0 0" />
    
                <Button Name="btnCancelParallel" Content="取消" Click="btnCancelParallel_Click_1" Margin="0 10 0 0" />
    
            </StackPanel>
        </Grid>
    </Page>
    复制代码

    Thread/Tasks/ParallelDemo.xaml.cs

    复制代码
    /*
     * Parallel - 并行计算(在 System.Threading.Tasks 命名空间下)
     * 
     * Parallel.For() - for 循环的并行运算 
     * Parallel.ForEach() - foreach 循环的并行运算 
     * Parallel.Invoke() - 并行调用多个 Action
     * PLINQ - LINQ to Object 的并行运算
     * 
     * 
     * 本例通过 Parallel.Invoke() 来演示并行运算
     * 其它并行运算的说明参见:http://www.cnblogs.com/webabcd/archive/2010/06/03/1750449.html
     */
    
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace XamlDemo.Thread.Tasks
    {
        public sealed partial class ParallelDemo : Page
        {
            private CancellationTokenSource _cts;
    
            public ParallelDemo()
            {
                this.InitializeComponent();
            }
    
            private void btnCreateParallel_Click_1(object sender, RoutedEventArgs e)
            {
                if (_cts != null)
                    _cts.Cancel();
                _cts = new CancellationTokenSource();
    
                // Parallel 的相关配置
                ParallelOptions parallelOptions = new ParallelOptions() 
                {
                    CancellationToken = _cts.Token, // Parallel 关联的 CancellationToken 对象,用于取消操作
                    MaxDegreeOfParallelism = 10 // Parallel 的最大并行数
                };
                
                // 并行执行多个 Action(不支持 Func)
                Parallel.Invoke(
                    parallelOptions,
                    () =>
                        Task1(parallelOptions.CancellationToken),
                    () =>
                        Task2(parallelOptions.CancellationToken));
            }
    
            // Action 1
            private void Task1(CancellationToken token)
            {
                Task task = Task.Factory.StartNew(
                    () =>
                    {
                        int count = 0;
                        // 未被取消则一直运行
                        while (!token.IsCancellationRequested)
                        {
                            count++;
    
                            var ignored = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg1.Text = "count1: " + count.ToString();
                                });
    
                            token.WaitHandle.WaitOne(100);
                        }
                    },
                    token);
            }
    
            // Action 2
            private void Task2(CancellationToken token)
            {
                Task task = Task.Factory.StartNew(
                    () =>
                    {
                        int count = 0;
                        // 未被取消则一直运行
                        while (!token.IsCancellationRequested)
                        {
                            count++;
    
                            var ignored = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
                                () =>
                                {
                                    lblMsg2.Text = "count2: " + count.ToString();
                                });
    
                            token.WaitHandle.WaitOne(100);
                        }
                    },
                    token);
            }
    
            // 取消并行运算
            private void btnCancelParallel_Click_1(object sender, RoutedEventArgs e)
            {
                if (_cts != null)
                    _cts.Cancel();
            }
        }
    }
  • 相关阅读:
    51nod 1179 最大的最大公约数 (数论)
    POJ 3685 二分套二分
    POJ 3045 贪心
    LIC
    HDU 1029 Ignatius and the Princess IV
    HDU 1024 Max Sum Plus Plus
    HDU 2389 Rain on your Parade
    HDU 2819 Swap
    HDU 1281 棋盘游戏
    HDU 1083 Courses
  • 原文地址:https://www.cnblogs.com/ansen312/p/5942882.html
Copyright © 2011-2022 走看看