在 C# 里面,可以使用 dotnet 的 TaskCompletionSource 方法自己实现一个异步任务,这个任务可以方便设置任务是否完成等做到让等待的过程继续或等待。 在A方法等待任务完成才继续往下走,而在 B 方法则设置任务完成 var taskCompletionSource = new TaskCompletionSource<bool> > await B(taskCompletionSource)).Wait(); private static async Task A(TaskCompletionSource<bool > taskCompletionSource) { Console.WriteLine("A 开始"); await taskCompletionSource.Task 而在业务设置了暂停,此时可以返回 taskCompletionSource 等待,在业务重新设置继续的时候,设置 SetResult 方法,此时就可以做到让功能继续 用这个方法在等待 TaskCompletionSource
在创建一个 TaskCompletionSource 期望让等待的逻辑只会被调用一次,而调用的是多线程,可以使用 TrySetResult 方法,这个方法是线程安全,只会让 TaskCompletionSource 被调用一次 在多个线程调用 TaskCompletionSource 的 TrySetResult 方法,只有一个线程能进入设置,其他线程将会拿到返回 false 的值 测试代码如下 _taskCompletionSource = new TaskCompletionSource<bool>(); Foo(); var taskList Console.Read(); private static async void Foo() { await _taskCompletionSource.Task ; Console.WriteLine("F"); } private static TaskCompletionSource<bool> _taskCompletionSource
TaskCompletionSource 中的异常 如果使用了 TaskCompletionSource,使用了类似这样的代码, var resultCompletionSource = new TaskCompletionSource (result); return result;}catch (Exception ex){ resultCompletionSource.SetException(ex); // 给 TaskCompletionSource resultCompletionSource.Task; }}catch (Exception e){ Console.WriteLine(e);} 背景问题原因 其实就是,虽然业务上处理了异常,但是有被“遗弃”的 TaskCompletionSource
这是先准备好的 TaskCompletionSource 对象 var btcReceivedTask = new TaskCompletionSource<bool>(); var worldBrokeTask = new TaskCompletionSource<bool>(); BtcMessage.KeyReceived += (sender 在 btcReceivedTask.SetResult 方法被调用之后,才会继续执行 await btcReceivedTask.Task; 之后的代码 于是在 TaskCompletionSource ; } private TaskCompletionSource<bool> TaskCompletionSource { get; } = new TaskCompletionSource ; 可以看到创建出来 WorldBrokeTask 然后接着等待就可以了,代码很简单 通过本文的例子相信大家也掌握了毁灭世界,哦,不,使用 TaskCompletionSource 封装事件为异步的方法
.NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件 2018-12-22 07:50 你可以使用临界区 使用 TaskCompletionSource,你可以轻松地编写既可以异步等待,又可以同步等待的代码来。 ---- 等待事件 我们创建一个 TaskCompletionSource<object> 对象,这样,我们便可以写出一个既可以同步等待又可以异步等待的方法: public class WalterlvDemo { private readonly TaskCompletionSource<object> _source = new TaskCompletionSource<object>(); 而 TaskCompletionSource<object> 提供了很多让任务完成的方法: ?
假定有一个 TaskCompletionSource 对象,此对象的 Task 没有被任何地方引用等待。 在 TaskCompletionSource 被调用 SetException 或 TrySetException 方法时,将会记录一个存在异常且未捕获的 Task 对象。 TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException; var taskCompletionSource = new TaskCompletionSource(); taskCompletionSource.SetException(new Exception()); } sender, UnobservedTaskExceptionEventArgs e) { } 以上是一个 WPF 应用,选 WPF 应用是可以比较方便等待 GC 的触发 以上代码将创建一个 TaskCompletionSource
使用TaskCompletionSource,Tasks可以利用回调的方式,在等待I/O绑定操作时完全避免使用线程。 5.TaskCompletionSource TaskCompletionSource也可以用来创建Task TaskCompletionSource让你在稍后开始和结束的任意操作中创建Task 它会为你提供一个可手动执行的 <TResult> { public TaskCompletionSource(); public TaskCompletionSource(object? state); public TaskCompletionSource(TaskCreationOptions creationOptions); public TaskCompletionSource 终极奥义 TaskCompletionSource自身创建Task,但并不占用线程(见示例代码) 特别需要说明的一点,Task中的Delay和Thread的Sleep不一样的是,Sleep不占用CPU处理资源而
实际上这里的本质就是使用了一个TaskCompletionSource。 TaskCompletionSource是一个task的封装源,代表了一个完成的task。 <bool>(); } } private TaskCompletionSource<bool> _source; private ManualResetEventAsync最重要的三个方法就是Set,Reset,和WaitOneAsync WaitOneAsync很简单就是等待TaskCompletionSource.Task。 如果TaskCompletionSource未标记完成则会等待,如果标记完成,则会继续执行 Set也很简单就是调用TaskCompletionSource.SetResult方法将其标记为完成,这样所有正在等待的 由于每个TaskCompletionSource的实例只能标识一次已完成,所以我们在每次重置时,需要重新实例化一个对象,进行替换。
发送补充成功"); }); app.Run(); public class PendingRequestManager { private ConcurrentDictionary<string, TaskCompletionSource <bool>> _pendingRequests = new(); public TaskCompletionSource<bool> Create(string userId) { var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); _pendingRequests[userId] = tcs; return tcs; } public TaskCompletionSource<bool>? TaskCompletionSource<T> 是 .NET 提供的一个可以手动控制 Task 何时完成的对象。
返回 Task 出去 var taskCompletionSource = new TaskCompletionSource<int>(); _queue.Enqueue (new BatchItem { Item = item, TaskCompletionSource = taskCompletionSource ,并且一批一批插入数据库,更新 TaskCompletionSource 的状态 private void RunBatchInsert() { <int> TaskCompletionSource { get; set; } public int Item { get; set; } } } } Item = item, TaskCompletionSource = taskCompletionSource });
实现方式和之前的异步版本ManualResetEvent基本相同,也是使用了一个TaskCompletionSource。 return CompletedSourceTask; } var source = new TaskCompletionSource <bool>> _waitQueue = new Queue<TaskCompletionSource<bool>>(); private bool _isSignaled 那么我们就不能一直使用同一个TaskCompletionSource进行等待。所以我们添加了一个队列维持TaskCompletionSource对象。 每次调用WaitOneAsync的时候就返回一个TaskCompletionSource的新实例。
private static async Task<bool> CheckDispatcherHangAsync(Dispatcher dispatcher) { var taskCompletionSource = new TaskCompletionSource<bool>(); _ = dispatcher.InvokeAsync(() => taskCompletionSource.TrySetResult (true)); await Task.WhenAny(taskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(2) )); // 如果任务还没完成,就是界面卡了 return taskCompletionSource.Task.IsCompleted is false;
connection) at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource connection) at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource `1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource
jsonSerializerSettings); request.AddParameter(“application/json”, jsonObject, ParameterType.RequestBody); TaskCompletionSource taskCompletion = new TaskCompletionSource(); RestRequestAsyncHandle handle = restClient.ExecuteAsync &LT; IRestResponse&GT; taskCompletion = new TaskCompletionSource&lt; IRestResponse&gt;(); RestRequestAsyncHandle taskCompletion = new TaskCompletionSource(); RestRequestAsyncHandle handle = restClient.ExecuteAsync &LT; IRestResponse&GT; taskCompletion = new TaskCompletionSource&lt; IRestResponse&gt;(); RestRequestAsyncHandle
也就是当不存在任何一个线程在等待 WaitOneAsync 时,再调用 Set 多次,然后如果有多个线程再调用 WaitOneAsync 时,只有一个线程能继续执行,其他线程需要等待 Set 方法调用 原理 使用 TaskCompletionSource 支持进行 await 时出让执行,此时的线程会等待 TaskCompletionSource 被调用 SetResult 方法才会继续执行 在调用 WaitOneAsync 的时候,创建一个 TaskCompletionSource 返回给代码用来 await 因此此时 TaskCompletionSource 没有设置 SetResult 方法,也就是代码等待将会出让执行 在调用 Set 方法时才调用其中一个 TaskCompletionSource return CompletedSourceTask; } var source = new TaskCompletionSource <bool>> _waitQueue = new Queue<TaskCompletionSource<bool>>(); private bool _isSignaled
在开发SilverLight时,弹窗一直都是用的回调方式,比如需要用户确认才能继续操作的,如果有好几个确认步骤,这时候回调函数就比较深了,代码基本看不懂,可以使用TaskCompletionSource System.Windows.MessageBoxResult> ShowAsync(string message, string title, MsgBoxButton buttons) { var taskResult = new TaskCompletionSource MsgBoxButton.YesNo, rs2 => { MessageBox.Show(rs2.ToString()); }); }); 参考资料 C# dotnet 使用 TaskCompletionSource
在.NET4.0下,有一个泛型类,叫TaskCompletionSource<TReuslt>,它能控制Task的行为,如给Task设置结果、设置异常、设置取消等。 ,实现代码如下: 1 public static Task Run(Action action) 2 { 3 var tcs = new TaskCompletionSource static Task<TResult> Run<TResult>(Func<TResult> function) 2 { 3 var tcs = new TaskCompletionSource 33 { 34 public static Task Run(Action action) 35 { 36 var tcs = new TaskCompletionSource static Task<TResult> Run<TResult>(Func<TResult> function) 51 { 52 var tcs = new TaskCompletionSource
Test(async () => { var mainWindow = new MainWindow(); var taskCompletionSource = new TaskCompletionSource(); mainWindow.Loaded += (sender, args) => taskCompletionSource.SetResult (); await mainWindow.Dispatcher.InvokeAsync(mainWindow.Show); await taskCompletionSource.Task Test(async () => { var mainWindow = new MainWindow(); var taskCompletionSource = new TaskCompletionSource(); mainWindow.Loaded += (sender, args) => taskCompletionSource.SetResult
我们来看看 TaskCompletionSource<TResulr> 类型的属性和方法: 属性: 属性 说明 Task 获取由此 Task 创建的 TaskCompletionSource。 TaskCompletionSource<TResulr> 类可以对任务的生命周期做控制。 TaskCompletionSource<int> task = new TaskCompletionSource<int>(); Task<int> myTask = task.Task 使用示例如下: static void Main() { TaskCompletionSource<int> task = new TaskCompletionSource / 实现一个支持同步和异步任务的类型 这部分内容对 TaskCompletionSource<TResult> 继续进行讲解。
var taskCompletionSource = new TaskCompletionSource<IList<Contact>>(); // 在cancellationToken 中注册lambda cancelToken.Value.Register(() => { // 我们收到一条取消消息,取消TaskCompletionSource.Task var taskCompletionSource = new TaskCompletionSource<IList<Contact>>(); // 在cancellationToken 中注册lambda cancelToken.Value.Register(() => { // 我们收到一条取消消息,取消TaskCompletionSource.Task stopLoad = true; taskCompletionSource.TrySetCanceled(); });