C# 如何使用特定的TaskScheduler使TaskCompletionSource.Task完成
当我调用C# 如何使用特定的TaskScheduler使TaskCompletionSource.Task完成,c#,.net,multithreading,task-parallel-library,C#,.net,Multithreading,Task Parallel Library,当我调用TaskCompletionSource.SetResult时,如何在特定的TaskScheduler上完成TaskCompletionSource.Task 目前,我正在使用我借鉴的想法: 静态公共任务ContinueOnTaskScheduler( 此任务(此,任务调度程序) { return@this.ContinueWith( 先行项=>先行项, 取消令牌。无, TaskContinuationOptions.Executes同步执行, 调度器)。展开(); } 因此,每当我将
TaskCompletionSource.SetResult
时,如何在特定的TaskScheduler
上完成TaskCompletionSource.Task
目前,我正在使用我借鉴的想法:
静态公共任务ContinueOnTaskScheduler(
此任务(此,任务调度程序)
{
return@this.ContinueWith(
先行项=>先行项,
取消令牌。无,
TaskContinuationOptions.Executes同步执行,
调度器)。展开();
}
因此,每当我将TaskCompletionSource.Task
返回给调用者时,我现在将返回TaskCompletionSource.Task.ContinueOnTaskScheduler(scheduler)
有没有可能通过某种方式避免另一个层次的间接的
继续?了解你在这背后的目标会很有趣。无论如何,如果您想避免使用ContinueWith
(我认为这是相当低的)的开销,您可能必须提出类似于TaskCompletionSource
的模式的您自己的版本
没那么复杂。例如,下面类似于Promise
的东西可以用与使用TaskCompletionSource
相同的方式使用,但允许提供自定义的TaskScheduler
来完成(免责声明:几乎未经测试):
另一方面,此版本具有对SetException(ExceptionDispatchInfo edi)
的覆盖,因此您可以从catch
内部传播活动异常的状态:
catch(Exception ex)
{
var edi = ExceptionDispatchInfo.Capture(ex);
promise.SetException(edi);
}
创建通用版本也很容易
不过,这种方法也有缺点。第三方可以执行promise.Task.Run
或promise.Task.RunSynchronously
,因为Task
在TaskStatus.Created
状态下公开
您可以将该检查添加到InvokeCompletionAction
,也可以使用嵌套的任务/code>Task.Unwrap
(尽管后者会带来一些开销)。请注意,您同时指定了TaskContinuationOptions.executes
和调度程序
。您是否知道,只有当此计划程序
与相同的同步上下文WAREtcs关联时,它才会同步完成。调用了SetResult
?否则它会排队。我知道,没关系。谢谢你的指点。
public class Promise
{
readonly Task _task;
readonly CancellationTokenSource _cts;
readonly object _lock = new Object();
Action _completionAction = null;
// public API
public Promise()
{
_cts = new CancellationTokenSource();
_task = new Task(InvokeCompletionAction, _cts.Token);
}
public Task Task { get { return _task; } }
public void SetCompleted(TaskScheduler sheduler = null)
{
lock(_lock)
Complete(sheduler);
}
public void SetException(Exception ex, TaskScheduler sheduler = null)
{
lock (_lock)
{
_completionAction = () => { throw ex; };
Complete(sheduler);
}
}
public void SetException(System.Runtime.ExceptionServices.ExceptionDispatchInfo edi, TaskScheduler sheduler = null)
{
lock (_lock)
{
_completionAction = () => { edi.Throw(); };
Complete(sheduler);
}
}
public void SetCancelled(TaskScheduler sheduler = null)
{
lock (_lock)
{
// don't call _cts.Cancel() outside _completionAction
// otherwise the cancellation won't be done on the sheduler
_completionAction = () =>
{
_cts.Cancel();
_cts.Token.ThrowIfCancellationRequested();
};
Complete(sheduler);
}
}
// implementation
void InvokeCompletionAction()
{
if (_completionAction != null)
_completionAction();
}
void Complete(TaskScheduler sheduler)
{
if (Task.Status != TaskStatus.Created)
throw new InvalidOperationException("Invalid task state.");
_task.RunSynchronously(sheduler?? TaskScheduler.Current);
}
}
catch(Exception ex)
{
var edi = ExceptionDispatchInfo.Capture(ex);
promise.SetException(edi);
}