C#学习笔记 任务操作

2023-11-16

利用线程,可以方便地进行异步操作。但是线程模型有一个缺点,就是无法处理返回值。要在不同线程之间传递数据比较麻烦。任务则解决了这个问题。

完整代码在这里:https://github.com/techstay/csharp-learning-note

创建并执行任务

有返回值和没有返回值的任务

要创建一个没有返回值的任务,只需要向Task类的构造函数传递一个参数列表和返回值都为空的委托(也就是Action委托)即可。构造好一个Task之后,就可以调用Start方法开始执行任务,就像Thread上调用Start一样。这样任务就会开始异步地执行了。

要等待任务完成,可以调用Wait方法,这样就会在该线程上阻塞直到Task完成。另外WaitAny和WaitAll方法接受一个Task数组,WaitAny方法会阻塞调用线程直到有一个Task任务完成,而WaitAll方法会阻塞调用线程直到所有任务完成。

另外,还可以像Task的构造函数传递一个TaskCreationOptions枚举来控制Task的构造和执行。详情可以查看MSDN文档。

Task task1 = new Task(() => Console.WriteLine("创建一个新任务..."));
task1.Start();
task1.Wait();
Task.Run(() => Console.WriteLine("直接运行一个新任务..."))
    .Wait();

要创建带有返回值的任务,需要创建一个泛型Task,并向其传入一个Function< TResult>委托。然后便可以执行任务,任务执行完成之后可以调用其Result属性查询任务执行的结果。如果此时任务还没有完成,调用Result的线程会阻塞直到任务完成。如果有异常发生,也会在这个时候抛出。

另外,由于创建一个任务并开始运行是非常常见的代码,所以Task类提供了一个Run方法,接受一个委托并立即创建并执行任务。

Task<int> intValue = Task.Run(() =>
{
    Console.WriteLine("创建一个任务并等待结果..");
    return 0;
});
Console.WriteLine($"任务的结果是:{intValue.Result}");

可以取消的任务

有时候任务运行的时间可能比较长,这个时候可能需要取消任务。这时候需要向任务传递一个CancellationToken,然后在需要取消的时候调用ThrowIfCancellationRequested方法,这样会抛出一个OperationCanceledException,并被封装到Task的AggregateException异常中并抛出。

首先来定义一个长时间运行的函数。在接到取消命令之后,任务就会被取消并抛出一个OperationCanceledException异常。这样可以区别正常运行结束的任务和非正常结束的任务。

internal static int SumWithLongTime(CancellationToken ct, int n)
{
    int sum = 0;
    for (int i = 1; i <= n; ++i)
    {
        sum += i;
        if (i % 50 == 0)
            Thread.Sleep(500);
        ct.ThrowIfCancellationRequested();
    }
    return sum;
}

然后就可以执行并取消任务了。这个任务会运行大约7秒钟,在3秒钟的时候开始取消。这样会抛出一个AggregateException异常,真正引发的异常可以由GetBaseException方法获得。

Console.WriteLine("开始长时间的计算并取消:");
CancellationTokenSource cts = new CancellationTokenSource();
sumResult = Task.Run(() => SumWithLongTime(cts.Token, 700));
Console.WriteLine("开始计算,大约3s之后取消...");
cts.CancelAfter(3000);
try
{
    Console.WriteLine($"计算结果是:{sumResult.Result}");
}
catch (AggregateException ae)
{
    Console.WriteLine(ae.Message);
    Console.WriteLine(ae.GetBaseException().Message);
}

执行多个任务

延续任务

当一个任务完成之后调用其Result属性,可能会阻塞调用线程直到任务完成,这样不利于资源的充分利用。这时候可以考虑使用延续任务,在一个任务完成之后启动新任务。

要使用延续任务,只需要在一个任务上调用ContinueWith方法并传递一个委托,委托的参数代表要延续的任务,可以在委托中使用参数来操作前一个任务。另外,延续任务还可以继续延续,任务内部会维护一个延续任务链。另外,还可以向ContinueWith方法传递一个TaskContinuationOptions枚举,指定延续任务的执行策略和方式。代码最后调用Wait方法防止在显示结果前退出程序。

Console.WriteLine("开始执行连续的任务:");
Task<int> sumResult = Task.Run(() => SumWithLongTime(500));
Task<int> otherTask = sumResult.ContinueWith(task => task.Result);
Task printTask = otherTask.ContinueWith(task => Console.WriteLine($"连续任务的结果是:{task.Result}"));
printTask.Wait();

任务和子任务

任务默认都是顶级任务,与在什么位置创建无关。但是如果在一个任务中创建了几个任务,并向其构造函数中传递了TaskCreationOptions.AttachedToParent枚举,这些任务就会变成子任务。这样一来,父任务只有在所有子任务完成之后才能完成,当然子任务也可以继续创建子任务。

Console.WriteLine("开始执行子任务...");
Task<int[]> parent = new Task<int[]>(() =>
{
    int[] results = new int[3];

    new Task(() => results[0] = SumWithLongTime(500), TaskCreationOptions.AttachedToParent).Start();
    new Task(() => results[1] = SumWithLongTime(600), TaskCreationOptions.AttachedToParent).Start();
    new Task(() => results[2] = SumWithLongTime(700), TaskCreationOptions.AttachedToParent).Start();
    return results;
});
parent.Start();
var finished = parent.ContinueWith(parentTask => Array.ForEach(parentTask.Result, Console.WriteLine));
Console.WriteLine("正在执行子任务...");
finished.Wait();
Console.WriteLine();

任务工厂

有时候需要启动并执行多个具有相同配置的任务,这时候可以创建一个任务工厂,将相同的配置传递进任务工厂并启动任务。要创建没有返回值的任务,使用非泛型的任务工厂;要创建特定返回值类型的任务,使用泛型的任务工厂。

这里利用任务工厂改写上面的子任务的代码。

Console.WriteLine("开始利用工厂执行子任务...");
Task<int[]> parent = new Task<int[]>(() =>
{
    int[] results = new int[3];
    TaskFactory factory = new TaskFactory(CancellationToken.None
        , TaskCreationOptions.AttachedToParent
        , TaskContinuationOptions.AttachedToParent
        , TaskScheduler.Current);
    factory.StartNew(() => results[0] = SumWithLongTime(500));
    factory.StartNew(() => results[1] = SumWithLongTime(600));
    factory.StartNew(() => results[2] = SumWithLongTime(700));
    return results;
});
parent.Start();
var finished = parent.ContinueWith(parentTask => Array.ForEach(parentTask.Result, Console.WriteLine));
Console.WriteLine("正在执行子任务...");
finished.Wait();
Console.WriteLine();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#学习笔记 任务操作 的相关文章

  • 如何将动态数据写入 MVC 3 Razor 中的页面布局?

    我有带有 Razor 引擎的 MVC 3 C 项目 将动态数据写入 Layout cshtml 的方法和最佳实践是什么 例如 也许我想在网站的右上角显示用户名 该名称来自会话 数据库或基于用户登录的任何内容 更新 我也在寻找将某些数据渲染到
  • 如何在 Asp.Net Core 6 中向类型化 HttpClient 添加承载令牌身份验证

    我正在尝试使用 ASP Net Core 6 设置一个 Web api 以便用户可以到达我的端点 然后我使用特权帐户在幕后的 D365 中执行一些工作 我正在使用类型化的 HTTP 客户端 但我不确定如何插入承载身份验证 以便来自该客户端的
  • 为什么迭代器类型推导失败? [复制]

    这个问题在这里已经有答案了 为什么这在 C 中不起作用 为什么我不能限制foo的参数为std vector
  • ASP.NET 如何在 Web API 中读取多部分表单数据?

    我将多部分表单数据发送到我的 Web API 如下所示 string example my string HttpContent stringContent new StringContent example HttpContent fil
  • 无法在 Visual Studio 2022 中启动调试适配器

    如果我创建一个启用了 Docker 支持的 ASP Core MVC 目标框架 5 0 并启动它 我会得到 发生一个或多个错误 无法启动调试适配器 附加信息可能会 在输出窗口中可用 操作被取消 这是调试输出 启用 DebugAdapterH
  • Python 相当于 Bit Twiddling Hacks 中的 C 代码?

    我有一个位计数方法 我正在尝试尽可能快地实现 我想尝试下面的算法位摆弄黑客 http graphics stanford edu seander bithacks html CountBitsSetParallel 但我不知道 C 什么是
  • C# 中输入按键

    我尝试了这段代码 private void textBox1 KeyPress object sender KeyPressEventArgs e if Convert ToInt32 e KeyChar 13 MessageBox Sho
  • 作为服务运行时未找到 PowerShell 模块

    我有一个项目 我将 Office 365 许可证分配给用户 有一个 Web 项目允许管理员查看可用许可证并为用户选择许可证 在后台 有一项服务每 15 分钟执行一次实际的许可证分配 以及许多其他任务 我们不直接分配许可证的原因是用户可能尚未
  • 我如何模拟 UserManager 和 RoleManager 进行单元测试

    我模拟了抽象类来测试类的具体方法 如下所示 var mock new Mock
  • 使用 ClosedXML 附加到 excel 文件

    我需要将新数据附加到使用 ClosedXML 创建的现有 Excel 文件中 如何使用 ClosedXML 附加到 Excel 文件 如何获取最后一条记录的行号并将其附加到该行号上 或者还有其他内容 Thanks 打开现有工作簿 然后使用L
  • 这个元组创建习惯有名字吗?

    On the 增加邮件列表 http lists boost org Archives boost 2014 06 214213 php LouisDionne 最近发布了以下创建类似元组的实体的巧妙技巧 include
  • 使用 C# 的异步 WebRequest

    您好 我有一个函数 它将 url Get 参数传递到网络服务器上的 php 文件 并等待文件的响应 通常需要 10 20 秒 我想将其放入一个循环中 因为我必须一次将这些 Get 请求发送到大约 5 个不同的 php 文件 但是当我尝试将其
  • 从 cin 读取整数序列并将它们存储在向量中

    这就是我读取整数的方法std cin并将它们存储在向量中 int number vector
  • 什么是 C++11 扩展 [-Wc++11-extensions]

    我需要一些帮助来了解此错误发生的位置 警告 非静态数据成员的类内初始化是 C 11 扩展 Wc 11 extensions 这是它来自的代码部分 typedef struct Hand bool straight false bool fl
  • C# XML 反序列化。将节点中的所有内部文本读取到字符串属性中

    我目前正在尝试修改我的类 以便我的模型上的文本属性包含某个节点的所有内部文本 text node 给我带来问题的 xml 示例是
  • 为什么在 C++ 类中的数据成员上使用像 m_ 这样的前缀?

    许多 C 代码使用语法约定来标记数据成员 常见的例子包括 m memberName对于公共成员 在所有使用公共成员的情况下 memberName对于私人会员或所有会员 其他人尝试强制使用this gt member每当使用数据成员时 根据我
  • SQL Server CE 不兼容的数据库版本

    我有一个 SQL Server CE 4 0 数据库 sdf文件 当我尝试从我的应用程序 WPF 对数据库进行查询时 出现以下错误 数据库版本不兼容 如果这是兼容文件 请运行修复 其他情况请参考文档 数据库版本 4000000 请求的版本
  • 从 git 签出后 nuget dll 丢失

    I have a C solution containing different projects On those projects I have some normal nuget packages like Newtonsoft Js
  • 使用 ImageResizer 获取图像尺寸的最佳方法

    我正在将现有的 MVC 4 网站从自制用户文件上传切换为在上传时使用 ImageResizer 调整文件大小 我在文档中看到我不应该使用 System Drawing 但我无法找出任何其他获取图像尺寸的方法 尺寸是来自原始图像还是调整大小的
  • 从最大到最小的3个整数

    我是 C 初学者 我使用 编程 使用 C 的原理与实践 第二版 问题如下 编写一个程序 提示用户输入三个整数值 然后以逗号分隔的数字顺序输出这些值 如果两个值相同 则应将它们排列在一起 include

随机推荐

  • C++函数模板基础

    今天给大家带来函数模板的内容 当我们面对 逻辑相同但类型不同 的问题时 比如整型相加和浮点型相加 使用函数模板可以提高代码利用率 起到事半功倍的效果 今天给大家分享蛋类型变量的函数模板 include
  • 关于C++对象模型(下)

    下篇主要讨论调用成员函数 访问成员变量的开销 及其特殊成员函数 数组 异常处理的讨论 这篇文章中出现的对象定义都出现在上篇中 全文在这里下载 文章内容转自 http tb blog csdn net TrackBack aspx PostI
  • 数据链路层六大协议详解

    数据链路层六大协议详解 一些假设 1 无限制的单工协议 乌托邦协议 五点假设 发送方 接收方 接受方 2 单工停 等协议 3 有噪声信道的单工协议 本文图片截取自 学堂在线 华南理工大学的计算机网络课程 一些假设 物理层 数据链路层和网络层
  • 视频格式无损/快速转换——ffmpeg(mkv等转mp4)

    非商业用途转载请务必注明出处 https blog csdn net qq 40491305 article details 103272651 最近用PR发现不支持mkv格式 需要转化为mp4 考虑到快速 无损以及我仅仅需要转码 懒得使用
  • java.lang.ArrayIndexOutOfBoundsException(数组越界)处理方法

    转发自https blog csdn net qq 34646449 article details 76146659 当你使用不合法的索引访问数组时会报数组越界这种错误 数组arr的合法错误范围是 0 arr length 1 当你访问这
  • 使用反射动态校验后台配置某字段是否允许为空

    背景 使用easyExcel读取数据 title不固定 后台可以配置title必填项 title顺序可改变 用户可以自定义title 不存储自定义信息即可 不报错 思路 不能使用easyExcel使用index的方式读取数据 改成value
  • 文件在使用FileChannel.map后不能被删除(Windows上)

    同事发现在Windows上使用FileChannel的map方法之后 不能够删除掉文件 我在Linux上试了一下 发现没这个问题 做个笔记 记录一下 import java io File import java io RandomAcce
  • Unity笔记之获取鼠标停留的UI和删除按键触发后引用、判断鼠标是否在UI上

    需求 鼠标放在UI上 需要获取这个UI物体 以方便进行其他操作 百度学习了半天 最终拿了一个大哥 添加链接描述 的内容 本文仅作为个人笔记 建议大家直接去这大哥的博客看 不过我记得好像也可以通过继承unity内部的鼠标事件接口获取到物体 但
  • java.io.StreamCorruptedException: invalid type code: AC错误解决

    最近做IO时 出现了一个我百思不得其解的错误 虽然经过一番 解决的bug 但是对于这一方面的底层知识还是有待去深入了解 借这个机会 好好学习一下 一般 可以使用ObjectInputStream把对象写出到文件 再使用ObjectOutpu
  • 五分钟告诉你什么是爬虫?

    1 什么是爬虫 把互联网比喻成一张网 那么爬虫就是网上爬行的蜘蛛 把网的节点比喻成一个个网页 爬虫爬取到就相当于访问了该页面 获取了其信息 爬虫可以通过一个节点之后 顺着节点连线 链接 继续爬行到下一个节点 即通过一个网页继续获取后续的网页
  • 直播 RTM 推流在抖音的应用与优化

    动手点关注 干货不迷路 背景 随着互联网技术以及网络基建的快速发展和普及 视频直播已经成为了一种越来越普遍的娱乐和社交方式 无论是个人还是企业 都可以通过视频直播平台进行直播活动 向观众展示自己的生活 工作或者产品 同时 视频直播也成为了一
  • sqlmap自动注入1(Target完整的超级详细 如有错误望指出)

    SQLmap的自动注入学习之路 1 是通过五种sql注入漏洞的检测技术 and select from select sleep 20 a 这是基于时间的盲注检测 看他返回的时间 可以在DVWA试试 sqlmap支持非常全面的 数据库管理系
  • 咬了一口苹果死去的计算机之父——图灵

    艾伦 麦席森 图灵 Alan Mathison Turing 1912年6月23日 1954年6月7日 英国数学家 逻辑学家 被称为计算机科学之父 人工智能之父 1910年左右的伦敦 1912年生于英国伦敦帕丁顿 家族成员里有三位当选过英国
  • 星网宇达-组合导航在ros系统中的使用方法

    1 安装差分天线 两个 组合导航主机 DTU模块 不使用基站GPS的定位精度是米级的 园区里面自己搭建基站用DTU进行数据传输精度可达到厘米级 也可以利用千寻基站进行定位 效果不清楚 2 根据 杆臂以及天线安装说明文档 进行天线安装和杆臂配
  • 数据分析03——矩阵常用计算方法和函数

    0 前言 数组 计算机领域的概念 矩阵 数学领域的概念 对于Numpy而言 矩阵是数组的分支 1 创建矩阵 字符串创建矩阵 mat1 np matrix 1 2 3 4 列表形式创建矩阵 mat2 np matrix 5 6 7 8 通过数
  • QTextDocument和QTextBlock

    QTextDocument QTextDocument是用于结构化富文本文档的容器 为样式文本和各种类型的文档元素 如列表 表格 框架和图像 提供支持 可以创建它们以在QTextEdit中使用 也可以独立使用 每个文档元素均由关联的格式对象
  • 可视化工具Netron介绍

    Netron是一种用于神经网络 深度学习和机器学习模型的可视化工具 它可以为模型的架构生成具有描述性的可视化 descriptive visualization 源码在 https github com lutzroeder netron
  • Taro安装、启动命令、创建项目、修改端口号以及如何在微信开发者工具内运行

    1 安装Taro开发工具 npm install g tarojs cli 或者yarn global add tarojs cli 使用npm可能会有一些报错的信息 建议使用cnpm安装 2 使用命令创建模板 taro init myAp
  • 教你如何基于Redis来实现高性能延时消息队列!

    最近在倒腾自建博客后端系统 需要用到延时任务的功能 但手头只有一套MySQL和Redis 如果搞一套MQ成本有点大 于是想着用redis实现延时消息队列 有些场景用数据库的定时扫表也能简单实现延时消息的功能 不过对于我这边的实际场景 比如计
  • C#学习笔记 任务操作

    利用线程 可以方便地进行异步操作 但是线程模型有一个缺点 就是无法处理返回值 要在不同线程之间传递数据比较麻烦 任务则解决了这个问题 完整代码在这里 https github com techstay csharp learning not