VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之C#多线程编程系列(五)- 使用任务并行(2)

>(() => TaskMethod("Task 4", 4)); var complexTask = Task.WhenAll(t1, t2); // 通过ContinueWith TaskContinuationOptions.OnlyOnFaulted的方式 如果task出现异常 那么才会执行该方法 var exceptionHandler = complexTask.ContinueWith(t => { WriteLine($"异常被捕捉:{t.Exception.Message}"); foreach (var ex in t.Exception.InnerExceptions) { WriteLine($"-------------------------- {ex.Message}"); } },TaskContinuationOptions.OnlyOnFaulted); t1.Start(); t2.Start(); ReadLine(); } static int TaskMethod(string name, int seconds) { WriteLine($"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}"); Sleep(TimeSpan.FromSeconds(seconds)); // 人为抛出一个异常 throw new Exception("Boom!"); return 42 * seconds; }

运行结果如下所示,需要注意的是,如果在ContinueWith()方法中捕获多个任务产生的异常,那么它的异常类型是AggregateException,具体的异常信息包含在InnerExceptions里面,要注意和InnerException区分。

1533785572866

1.9 并行运行任务#

本节中主要介绍了两个方法的使用,一个是等待组中全部任务都执行结束的Task.WhenAll()方法,另一个是只要组中一个方法执行结束都执行的Task.WhenAny()方法。

具体使用,如下演示代码所示。


	
Copy
static void Main(string[] args) { // 第一种方式 通过Task.WhenAll 等待所有任务运行完成 var firstTask = new Task<int>(() => TaskMethod("First Task", 3)); var secondTask = new Task<int>(() => TaskMethod("Second Task", 2)); // 当firstTask 和 secondTask 运行完成后 才执行 whenAllTask的ContinueWith var whenAllTask = Task.WhenAll(firstTask, secondTask); whenAllTask.ContinueWith(t => WriteLine($"第一个任务答案为{t.Result[0]},第二个任务答案为{t.Result[1]}"), TaskContinuationOptions.OnlyOnRanToCompletion); firstTask.Start(); secondTask.Start(); Sleep(TimeSpan.FromSeconds(4)); // 使用WhenAny方法 只要列表中有一个任务完成 那么该方法就会取出那个完成的任务 var tasks = new List<Task<int>>(); for (int i = 0; i < 4; i++) { int counter = 1; var task = new Task<int>(() => TaskMethod($"Task {counter}",counter)); tasks.Add(task); task.Start(); } while (tasks.Count > 0) { var completedTask = Task.WhenAny(tasks).Result; tasks.Remove(completedTask); WriteLine($"一个任务已经完成,结果为 {completedTask.Result}"); } ReadLine(); } static int TaskMethod(string name, int seconds) { WriteLine($"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}"); Sleep(TimeSpan.FromSeconds(seconds)); return 42 * seconds; }

运行结果如下图所示。

1533793481274

1.10 使用TaskScheduler配置任务执行#

Task中,负责任务调度是TaskScheduler对象,FCL提供了两个派生自TaskScheduler的类型:线程池任务调度器(Thread Pool Task Scheduler)同步上下文任务调度器(Synchronization Scheduler)。默认情况下所有应用程序都使用线程池任务调度器,但是在UI组件中,不使用线程池中的线程,避免跨线程更新UI,需要使用同步上下文任务调度器。可以通过执行TaskSchedulerFromCurrentSynchronizationContext()静态方法来获得对同步上下文任务调度器的引用。

演示程序如下所示,为了延时同步上下文任务调度器,我们此次使用WPF来创建项目。

MainWindow.xaml 代码如下所示。


	
Copy
<Window x:Class="Recipe9.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Recipe9" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <TextBlock Name="ContentTextBlock" HorizontalAlignment="Left" Margin="44,134,0,0" VerticalAlignment="Top" Width="425" Height="40"/> <Button Content="Sync" HorizontalAlignment="Left" Margin="45,190,0,0" VerticalAlignment="Top" Width="75" Click="ButtonSync_Click"/> <Button Content="Async" HorizontalAlignment="Left" Margin="165,190,0,0" VerticalAlignment="Top" Width="75" Click="ButtonAsync_Click"/> <Button Content="Async OK" HorizontalAlignment="Left" Margin="285,190,0,0" VerticalAlignment="Top" Width="75" Click="ButtonAsyncOK_Click"/> </Grid> </Window>

MainWindow.xaml.cs 代码如下所示。


	
Copy
/// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } // 同步执行 计算密集任务 导致UI线程阻塞 private void ButtonSync_Click(object sender, RoutedEventArgs e) { ContentTextBlock.Text = string.Empty; try { string result = TaskMethod().Result; ContentTextBlock.Text = result; } catch (Exception ex) { ContentTextBlock.Text = ex.InnerException.Message; } } // 异步的方式来执行 计算密集任务 UI线程不会阻塞 但是 不能跨线程更新UI 所以会有异常 private void ButtonAsync_Click(object sender, RoutedEventArgs e) { ContentTextBlock.Text = string.Empty; Mouse.OverrideCursor = Cursors.Wait; Task<string> task = TaskMethod(); task.ContinueWith(t => { ContentTextBlock.Text = t.Exception.InnerException.Message; Mouse.OverrideCursor = null; }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext()); } // 通过 异步 和 FromCurrentSynchronizationContext方法 创建了线程同步的上下文 没有跨线程更新UI private void ButtonAsyncOK_Click(object sender, RoutedEventArgs e) { ContentTextBlock.Text = string.Empty; Mouse.OverrideCursor = Cursors.Wait; Task<string> task = TaskMethod(TaskScheduler.FromCurrentSynchronizationContext()); task.ContinueWith(t => Mouse.OverrideCursor = null, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); } Task<string> TaskMethod() { return TaskMethod(TaskScheduler.Default); } Task<string> TaskMethod(TaskScheduler scheduler) { Task delay = Task.Delay(TimeSpan.FromSeconds(5)); return delay.ContinueWith(t => { string str = $"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}"; Console.WriteLine(str); ContentTextBlock.Text = str; return str; }, scheduler); } }

运行结果如下所示,从左至右依次单击按钮,前两个按钮将会引发异常。 1533806840998

具体信息如下所示。

1533794812153

参考书籍

本文主要参考了以下几本书,在此对这些作者表示由衷的感谢,感谢你们为.Net的发扬光大所做的贡献!

  1. 《CLR via C#》
  2. 《C# in Depth Third Edition》
  3. 《Essential C# 6.0》
  4. 《Multithreading with C# Cookbook Second Edition》
  5. 《C#多线程编程实战》

源码下载点击链接 示例源码下载

笔者水平有限,如果错误欢迎各位批评指正!

本来想趁待业期间的时间读完《Multithreading with C# Cookbook Second Edition》这本书,并且分享做的相关笔记;但是由于笔者目前职业规划和身体原因,可能最近都没有时间来更新这个系列,没法做到几天一更。请大家多多谅解!但是笔者一定会将这个系列全部更新完成的!感谢大家的支持!

作者:InCerry

出处:https://www.cnblogs.com/InCerry/p/9450493.html

本站使用「署名 4.0 国际」创作共享协议,转载请在文章明显位置注明作者及出处。



相关教程
关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们       黑ICP备07002182号