【C# Task】TaskCompletionSource
TaskCompletionSource具体功能
用于封装一个没有不带委托的任务实列。可以在其他线程控制该任务实列什么时候结束、取消、错误。类似于EventWaitHandle的功能。
属性
Task
方法
- SetCanceled:将TaskCompletionSource.Task 转换为Cancel状态。
- SetException:将TaskCompletionSource.Task 转换为Faluted状态。
- SetResult:将TaskCompletionSource.Task 转换为RanToCompletion状态。
- TrySetCanceled
- TrySetException
- TrySetResult
TaskCompletionSource应用
TaskCompletionSource :表示未绑定委托的 Task 的制造者方,并通过 Task 属性提供对使用者方的访问。
由TaskCompletionSource创建的任务的状态是由TaskCompletionSource上的方法显式控制的。
TaskCompletionSource的所有成员都是线程安全的,可以在多个线程中并发使用。
https://blog.csdn.net/Czhenya/article/details/120442315
1、 使用 TaskCompletionSource 实现暂停功能
案例:火车票选购>选好车票>支付(软件界面暂停)>跳到支付页面>支付成功( 支付页面继续执行)>跳到支付页面
TaskCompletionSource<bool> tcs = new();
Task.Run(async () => await ChoiceTicket(tcs));
Task.Run(async () => await PayForMoney(tcs)); Console.Read();
//选择车票
static async Task<bool> ChoiceTicket(TaskCompletionSource<bool> tcs)
{ Console.WriteLine("选购火车票") ;
Console.WriteLine("跳转到到支付页面"); await tcs.Task;
Console.WriteLine("订票完成");
return tcs.Task.Result;
} //选择支付页面
static async Task PayForMoney(TaskCompletionSource<bool> tcs)
{ await Task.Delay(3000).ContinueWith((t) => Console.WriteLine("选购支付宝支付")); tcs.SetResult(true);
Console.WriteLine("支付完成");
Console.WriteLine("跳到火车票软件完成");
}
通过控制台可以看到先输出 A 开始 然后等待一秒输出 B 开始 之后调用了 SetResult 方法,然后输出 A 完成 也就是 A 方法在 await taskCompletionSource.Task 等待直到 B 调用 taskCompletionSource.SetResult(true) 方法才继续往下
2、将回调(事件)封装为任务完成源
作用:使得代码更容易阅读和维护
事件完成后调用回调方法
在之前的指南中,我们讨论了生成图像的应用程序;假设您需要应用程序将这些图像上传到某个地方。假设有一个名为"MyBox"的云文件存储服务,它有一个.NET库,上传文件的库方法如下:
public static void UploadFile(string name, byte[] data, Action<bool> onCompleted);
查阅库的文档后,您会发现onCompleted是在上载完成时调用的回调,如果上载成功,则值为true,如果上载失败,则值为false。若要使用此库方法上载文件,必须执行如下操作,前提是您的应用程序具有可显示名为statusText的文本的内容:
public async void OnUploadButtonClicked()
{
statusText.Text = "Generating Image...";
byte[] imageData = await GenerateImage();
statusText.Text = "Uploading Image...";
MyBox.UploadFile("image.jpg", imageData, success =>
{
statusText.Text = success ? string.Empty : "Error Uploading";
});
}
修改成TaskCompletionSource
public static Task<bool> UploadFile(string name, byte[] data)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
try
{
MyBox.UploadFile(name, data, success =>
{
taskCompletionSource.SetResult(success);
});
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
return taskCompletionSource.Task;
}
public async void OnUploadButtonClicked()
{
statusText.Text = "Generating Image...";
byte[] imageData = await GenerateImage();
statusText.Text = "Uploading Image...";
bool success = await MyBoxHelper.UploadFile("image.jpg", imageData);
statusText.Text = success ? string.Empty : "Error Uploading";
}
像同步一样写代码。简直不要太爽。
创建TaskCompletionSource时建议使用TaskCreationOptions.RunContinuationsAsynchronously属性
对于编写类库的人来说TaskCompletionSource<T>是一个具有非常重要的作用,默认情况下任务延续可能会在调用try/set(Result/Exception/Cancel)的线程上进行运行,这也就是说作为编写类库的人来说必须需要考虑上下文,这通常是非常危险,可能就会导致死锁' 线程池饥饿 *数据结构损坏(如果代码异常运行)
所以在创建TaskCompletionSourece<T>时,应该使用TaskCreationOption.RunContinuationAsyncchronously参数将后续任务交给线程池进行处理
下面例子就没有使用TaskCreationOptions.RunComtinuationsAsynchronously,
static void Main(string[] args)
{
ThreadPool.SetMinThreads(100, 100);
Console.WriteLine("Main CurrentManagedThreadId:" + Environment.CurrentManagedThreadId);
var tcs = new TaskCompletionSource<bool>();
// 使用TaskContinuationOptions.ExecuteSynchronously来测试延续任务
ContinueWith(1, tcs.Task);
// 测试await延续任务
ContinueAsync(2, tcs.Task);
Task.Run(() =>
{
Console.WriteLine("Task Run CurrentManagedThreadId:" + Environment.CurrentManagedThreadId );
tcs.TrySetResult(true);
});
Console.ReadLine();
}
static void print(int id) => Console.WriteLine($"continuation:{id}\tCurrentManagedThread:{Environment.CurrentManagedThreadId}");
static async Task ContinueAsync(int id, Task task)
{
await task.ConfigureAwait(false);
print(id);
}
static Task ContinueWith(int id, Task task)
{
return task.ContinueWith(
t => print(id),
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
️所以应该改为使用TaskCreationOptions.RunComtinuationsAsynchronously参数进行设置TaskCompletionSoure
static void Main(string[] args)
{
ThreadPool.SetMinThreads(100, 100);
Console.WriteLine("Main CurrentManagedThreadId:" + Environment.CurrentManagedThreadId);
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
// 使用TaskContinuationOptions.ExecuteSynchronously来测试延续任务
ContinueWith(1, tcs.Task);
// 测试await延续任务
ContinueAsync(2, tcs.Task);
Task.Run(() =>
{
Console.WriteLine("Task Run CurrentManagedThreadId:" + Environment.CurrentManagedThreadId);
tcs.TrySetResult(true);
});
Console.ReadLine();
}
static void print(int id) => Console.WriteLine($"continuation:{id}\tCurrentManagedThread:{Environment.CurrentManagedThreadId}");
static async Task ContinueAsync(int id, Task task)
{
await task.ConfigureAwait(false);
print(id);
}
static Task ContinueWith(int id, Task task)
{
return task.ContinueWith(
t => print(id),
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
【C# Task】TaskCompletionSource的更多相关文章
- 【C# Task】开篇
概览 在学task类之前必须学习线程的知识. 以下是task命名空间的类的结构图 1.2种任务类型: 有返回值task<TResult> .无返回值task. 2.2座任务工厂 TaskF ...
- 【C# task】TaskContinuationOptions 位枚举
TaskContinuationOptions 根据 TaskContinuationOptions 的不同,出现了三个分支 LongRunning:独立线程,和线程池无关 包含 PreferFair ...
- 【Spring Task】定时任务详解实例-@Scheduled
Spring的任务调度,采用注解的形式 spring的配置文件如下,先扫描到任务的类,打开spirng任务的标签 <beans xmlns="http://www.springfram ...
- 【C# Task】 ValueTask/Task<TResult>
概要 1.如果异步方法的使用者使用 Task.WhenAll 或 Task.WhenAny,则在异步方法中使用 ValueTask<T> 作为返回类型可能会产生高昂的成本.这是因为您需要使 ...
- 【C# Task】理解Task中的ConfigureAwait配置同步上下文
原文:https://devblogs.microsoft.com/dotnet/configureawait-faq/ 作者:Stephen 翻译:xiaoxiaotank 静下心来,你一定会有收获 ...
- 【C#Task】TaskCreationOptions 枚举
根据 TaskCreationOptions 的不同,出现了三个分支 LongRunning:独立线程,和线程池无关 包含 PreferFairness时:preferLocal=false,进入全局 ...
- 【C# Task】System.Threading.Channels 生产者和消费者模式
前言 今天给大家分享一个微软官方的生产者/消费者方案的特性解决:Channel. Channel在% dotnet add package System.Threading.Channels 而在Co ...
- 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程
反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) 背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...
- 【30.93%】【codeforces 558E】A Simple Task
time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...
随机推荐
- 【失败的经验】在linux下编译opencv for android
cd /home/ahfu#选择opencv 3.4.6版本来编译wget https://github.com/opencv/opencv/archive/3.4.6.tar.gztar -zxvf ...
- WebGPU | 相关知识概述
首先看下WebGPU的目标: 同时支持实时屏幕渲染和离屏渲染. 使通用计算能够在 GPU 上高效执行. 支持针对各种原生 GPU API 的实现:Microsoft 的 D3D12.Apple 的 M ...
- 适配器模式(Adapter模式)
模式的定义与特点 适配器模式(Adapter)的定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作.适配器模式分为类结构型模式和对象结构型模式 ...
- golang中goroutine池的使用
1. 概念本质上是生产者.消费者模型可以有效的控制goroutine数量,防止暴涨案例:生成一个随机数,计算该随机数每一个数字相加的和,例如:123:1+2+3=6主协程负责生产数据发送到待处理通道中 ...
- BugKu-杂项(Misc)的部分Writeup(持续更新)
第一次写博客,有不好的地方,麻烦大佬指正,我用了些时间把BugKu里的Misc的解题思路和套路整理了一下,发出来分享 各位小可爱们,右边有目录可以快速跳转哦 1.签到题 给了一张二维码,扫描关注就得到 ...
- 感恩陪伴 HelloGitHub 定制的红包封面
距离放假越来越近了,我们更文的频率也越来越低了. 先别打!听我解释... 我真没偷懒,我是去研究今年的「微信红包封面」玩法了. 这不去年,我们制作的 HelloGitHub 专属红包封面,很多粉丝都说 ...
- jsp中获取下拉框的value问题
遇到问题 最近快期末考试了,今天想写一个简单的增删改查项目练练手,可是在刚写增加的时候就出现了问题,"增"一直是最简单的操作,本来自付很快就能写完,可是数据库中对应的下拉框数据一直 ...
- python03day
回顾 pycharm简单使用 while循环 结构 pass while实现打印1-2+3-4+--+99 格式化输出:针对str,让字符串中某些位置变为动态可传入的 % s str d digist ...
- 洛谷P1002过河卒java100分题解
题目描述如图: 这道题我以前以回溯的方法做,只能拿到60分 现在才发现是道动态规划题 解题思路: 创建一个(0,0)到终点打小的二维数组表示棋盘 每个坐标的值为此位置到终点的路数 最下方一排和最右方一 ...
- JavaScripts之迪卡算法求积(n*n)适用于SKU信息计算等场景
迪卡算法求积(n * n) 使用 array.reduce 的方式实现 笛卡尔积算法 const arr = [ ['黑色', '白色', '蓝色'], ['1.2KG', '2.0KG', '3.0 ...