【发布时间】:2015-02-05 09:28:25
【问题描述】:
我正在编写一个库,其中包括基于 .Net 任务的调度功能(不是标准的 TaskScheduler、IScheduler...)。我正在使用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 继承并覆盖成员(使用 new),但如果可能的话,最好给图书馆用户一个实际的 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 表达式转换为委托类型“System.Func”,因为块中的某些返回类型不能隐式转换为委托返回类型
* 无法将类型“System.Threading.Tasks.Task”隐式转换为“TResult”
【问题讨论】:
-
我想我已经回答了一个密切相关的问题here。
-
我认为,如果您想拥有更多控制权,您的 API 不应基于
Task,而应基于自定义类,该类准确地公开您想要公开的信息。您也可以公开Task,但状态信息将来自您自己的班级。 -
@Noseratio:链接代码中的
Task仅经历两种状态:Created和“已完成”,类似于TaskCompletionSource.Task仅经历两种状态(WaitingForActivation和“已完成” ”)。我需要 3 个状态(Created、Running、“已完成”),并且我上面的示例代码尝试使用 async-await 来完成此操作,但正如所解释的那样由于类型而不起作用不匹配。我看不到如何修改您的链接代码以支持 3 状态 - 有什么想法吗? -
@usr: 是的,我可以使用自定义状态信息创建自己的可等待对象,但我在很多地方都使用常规(非代理)任务,并希望呈现单个(标准,即任务)可等待类型给图书馆用户。关于第二个建议:给用户一个任务(具有状态)和我自己的单独状态属性也会令人困惑和不受欢迎。如果我误解了什么,请告诉我。
-
@KristianWedberg 我明白了。我认为这是对 TPL 的滥用,以仅在您的调度库中存在的概念来重载内部状态代码。我会创建一个
class ScheduledTask { MyStatusEnum Status; Task Completed; }。尽管我认为这是一种反模式,但您甚至可以使这种类型成为可等待的。无论如何,您的问题是有效的,应该按要求回答。
标签: c# .net task-parallel-library async-await