gpt4 book ai didi

c# - 创建冰冷的 TaskCompletionSource?

转载 作者:太空狗 更新时间:2023-10-29 17:50:35 27 4
gpt4 key购买 nike

我正在编写一个库,其中包含基于 .Net 任务的调度功能(不是标准的 TaskSchedulerIScheduler ...)。我正在使用 TaskCompletionSource , 和 Task.Status对于表示基础操作的状态至关重要,包括 TaskStatus.Created ,即已创建但尚未开始。我知道返回的任务通常应该很热,但对于我手动控制的代理任务,我确实希望它们最初是 Created .

对我来说不幸的是,TaskCompletionSource.Task 的初始状态是WaitingForActivation ,即它已经过去了 Created .换句话说,TaskCompletionSource支持两种状态,但我需要三种状态:

问题:如何获得 Task我可以手动设置为三个 不同的状态? IE。 Task.Status可以设置为:

1) Created
2) WaitingForActivation之一/WaitingForChildrenToComplete/WaitingToRun/Running
3) RanToCompletion 之一/Canceled/Faulted

下面的代码提示类型不匹配是可以理解的。我可以通过更改 new Task<TResult> 来包装任务至 new Task<Task<TResult>> , 但要回到 Task<TResult>我必须 Unwrap()它,并且展开的任务将具有状态 WaitingForActivation ,让我回到原点。

我会有很多这样的东西,所以用 Wait() 阻塞了一个线程对于每个都不是一个选项。

我考虑过继承Task和覆盖成员(使用新的),但如果可能的话,最好给图书馆用户一个实际的 Task而不是 DerivedTask ,特别是因为我提出了在许多其他地方也等待的常规任务。

想法?

private TaskCompletionSource<TResult> tcs;

private async Task<TResult> CreateStartCompleteAsync()
{
await tcs.Task;
if (tcs.Task.IsCanceled)
{
throw new OperationCanceledException("");
}
else if // etc.
}

public ColdTaskCompletionSource()
{
tcs = new TaskCompletionSource<TResult>();
Task = new Task<TResult>(() => CreateStartCompleteAsync());
}

错误:
* 无法将 lambda 表达式转换为委托(delegate)类型“System.Func”,因为 block 中的某些返回类型不能隐式转换为委托(delegate)返回类型
* 无法将类型“System.Threading.Tasks.Task”隐式转换为“TResult”

最佳答案

虽然我同意@usr 在评论中的观点,但从技术上讲,您仍然可以拥有提供这些状态的实现:

  1. 已创建
  2. 等待运行
  3. RanToCompletion/Canceled/Faulted

要避免使用 Task.Wait 阻塞线程,您可以使用内部助手 TaskScheduler,它会首先将任务从 Created 转移到WaitingToRun 并最终进入完成状态之一。

下面的代码说明了这个概念。它只进行了非常轻微的测试,可能不是完全线程安全的,也许可以改进以在多个任务之间共享单个 FakeTaskScheduler 实例。

public class ColdTaskCompletionSource
{
public sealed class FakeTaskScheduler : TaskScheduler
{
Task _task;

public FakeTaskScheduler()
{
}

protected override void QueueTask(Task task)
{
_task = task;
}

protected sealed override bool TryDequeue(Task task)
{
if (task != _task)
return false;

_task = null;
return true;
}

protected override IEnumerable<Task> GetScheduledTasks()
{
if (_task == null)
yield break;
yield return _task;
}

protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false;
}

public override int MaximumConcurrencyLevel
{
get { return 1; }
}

public bool Execute()
{
if (_task == null)
return false;

var task = _task;
_task = null;
return base.TryExecuteTask(task);
}
}

readonly Task _task;
readonly CancellationTokenSource _cts;
readonly object _lock = new Object();
readonly FakeTaskScheduler _ts = new FakeTaskScheduler();
Action _completionAction = null;

// helpers

void InvokeCompletionAction()
{
if (_completionAction != null)
_completionAction();
}

void Complete()
{
if (_task.Status != TaskStatus.WaitingToRun)
throw new InvalidOperationException("Invalid Task state");
_ts.Execute();
}

// public API

public ColdTaskCompletionSource()
{
_cts = new CancellationTokenSource();
_task = new Task(InvokeCompletionAction, _cts.Token);
}

public Task Task { get { return _task; } }

public void Start()
{
_task.Start(_ts);
}

public void SetCompleted()
{
lock (_lock)
Complete();
}

public void SetException(Exception ex)
{
lock (_lock)
{
_completionAction = () => { throw ex; };
Complete();
}
}

public void SetCancelled()
{
lock (_lock)
{
_completionAction = () =>
{
_cts.Cancel();
_cts.Token.ThrowIfCancellationRequested();
};
Complete();
}
}
}

关于c# - 创建冰冷的 TaskCompletionSource?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28319630/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com