【C# Task】TaskCompletionSource

TaskCompletionSource具体功能

用于封装一个没有不带委托的任务实列。可以在其他线程控制该任务实列什么时候结束、取消、错误。类似于EventWaitHandle的功能。

属性

Task

方法

TaskCompletionSource应用

TaskCompletionSource :表示未绑定委托的 Task 的制造者方,并通过 Task 属性提供对使用者方的访问。

由TaskCompletionSource创建的任务的状态是由TaskCompletionSource上的方法显式控制的。

TaskCompletionSource的所有成员都是线程安全的,可以在多个线程中并发使用。

https://blog.csdn.net/Czhenya/article/details/120442315

 

1、 使用 TaskCompletionSource 实现暂停功能

案例:火车票选购>选好车票>支付(软件界面暂停)>跳到支付页面>支付成功( 支付页面继续执行)>跳到支付页面

简单的使用例子如下,有两个方法在两个不同的线程,此时在 A 线程调用 A 方法,而在 B 线程调用 B 方法。在A方法等待任务完成才继续往下走,而在 B 方法则设置任务完成

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";
}

像同步一样写代码。简直不要太爽。

 

编程是个人爱好

推荐这些文章:

C# 异步方法

问题
在写基于任务的异步方法,遇到关于async、await的问题。
如下,写2个函数。F1()、F2(),差别是F1有async修饰。

 
问题1:
  为何F1有async修饰,就不需要return值了?而F2却提示我没有返回值?
  据我所知,async的作用是为了函数内能用await,是个编译器功能,并没有其它什么功能了啊。

 
问题2:
    明明 t 是异步执行的,为何提示却说是同步执行??

 
问题3:
  我给F2加了返回值,又写了个F3,请问F2和F3现在是不是一样的??
 
 

 ...

C#Task简单描述

一、Thread (System.Threading)

1.前台线程和后台线程
只要有一个前台线程在运行,应用程序的进程就在运行,直到所有前台线程完成其任务为止。在默认情况下,用 Thread类创建的线程是前台线程。线程池中的线程总是后台线程。在用 Thread类创建线程时,可以设置 IsBackground属性,以确定该线程是前台线程还是后台线程(默认为false)。
2.控制线程
调用 Thread对象的Start()方法,可以创建线程。但是,在调用Start()方法后,新线程仍不是处于 Running状态,而是处于 Unstar...

C#多线程异常处理(四)

在线程执行的地方使用try..catch..捕获不到异常首先,线程内部不应该出现异常,所以首选处理方式是在Task中使用try..catch..把异常处理掉Task中可能会抛出多个异常,应该使用AggregateException捕获多线程中所有异常。AggregateException是一个集合
wait()、Result
在调用Task的Wait()方法或Result属性处会抛出Task中的异常。
使用ContinueWith捕获异常
如果不可以在内部捕获,可以使用ContinueWith()方法捕获异常
var t = Task.Run<int>(() =>
...

C#使用异步操作时的注意要点(翻译)

异步操作时应注意的要点

使用异步方法返回值应避免使用void
对于预计算或者简单计算的函数建议使用Task.FromResult代替Task.Run
避免使用Task.Run()方法执行长时间堵塞线程的工作
避免使用Task.Result和Task.Wait()来堵塞线程
建议使用await来代替continueWith任务
创建TaskCompletionSource时建议使用TaskCreationOptions.RunContinuationsAsynchronously属性
建议使用CancellationTokenSource(s)进行超时管理时总是释放(dispose)
建议...

C#线程基础知识2

static void Main(string[] args)
{
new Thread(Go).Start();//在分线程上 调用Go()

Go();//在main线程上 调用Go()

Console.ReadKey();
}

public static void Go()
{
//cycles是本地变量,在每个线程的内存栈上,都会创建cycles独立的副本。(线程之间不共享数据)
for (int...

C#异步操作的知识点

#region 使用Task对象中的T返回异步方法里面的值,也可以是获取异步的状态。
//class Program
//{
// static void Main(string[] args)
// {
// Task value = DoAsyncStuff.CalculateSumAsync(5, 6);
// Console.WriteLine($"Value:{value.Result}");
// Console.ReadLine();
...

【C#】超时取消 CancellationToken

Console.WriteLine("有个人去4s店买车");

var tokenSource = new CancellationTokenSource();

// 下单买车,但是不确定要多久才能提车
var task1 = DoSomething(tokenSource.Token);

// 这个人的耐心只有五秒钟
var task2 = Task.Delay(5000);

// 提车和耐心上限的某一个成功了。
var res = await Task.WhenAny(task1, task2);

// 等了5秒,判断结果到底是提车还是等不下去
if (res != task...

C# Task 使用 WhenAll 和 WaitAll 需要注意的坑

1.无限等待
我们在使用 WhenAll 和 WaitAll 时,一定得要注意:1.必须添加超时时间,防止无限等待 2.等待的 Task 一定要保证是启动的。
比如下面这种写法:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TaskForWhenAll
{
class Program
{
static void Main(string[] args)
{
var taskList = ne...

## 使用C# 6.0中的async/await

异步函数是TPL之上更高级别的抽象,真正简化了异步编程,它与普通函数不一样在于必须有async标识,并且返回类型一般是Task<T>,Task类型,当然也可以使用async void,但更推荐使用async Task,使用async void唯一合理的地方在于程序中使用顶层UI控制器事件处理器的时候。
在异步函数内部,必须至少有一个await操作符,该操作符一般与TPL一起工作,并获取该任务中的异步操作的结果。需要注意的是在执行完await调用的代码行后该方法会立即返回,剩下的异步函数的部分独立异步运行,值得注意的是如果程序中有两个连续的await操作符,它们是顺序运行的,即第一...

C# 通过反射获取async方法返回值

首先,先看看非异步方法如何获得。
class Program
{
static void Main(string[] args)
{
MethodInfo methodInfo = typeof(Program).GetMethod("SayHello");

object result = methodInfo.Invoke(new Program(), new object[] { "张三" });

Console.ReadKey();
}

public string SayHello(string na...

文章标题:【C# Task】TaskCompletionSource
文章链接:https://www.dianjilingqu.com/51325.html
本文章来源于网络,版权归原作者所有,如果本站文章侵犯了您的权益,请联系我们删除,联系邮箱:saisai#email.cn,感谢支持理解。
THE END
< <上一篇
下一篇>>