【发布时间】:2013-12-24 17:48:36
【问题描述】:
这是一个“学术”问题,而不是影响我目前以官方身份从事的任何工作的问题,但我认为这里有人可以向我解释这一点。
我在LinqPAD 中使用CancellationToken(我提到这个细节是为了让不熟悉它的人知道Dump() 基本上是Console.WriteLine() 的简写),我正在尝试一个场景,我在我的任务完成时让主线程休眠。这是在运行多个取消任务的变体之后完成的,然后才能完成使用IsCanceled 属性并验证Result 属性在取消时不可访问。这是我的虚拟 LinqPAD 程序的样子:
void Main()
{
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => Test())
.ContinueWith(t => t.Result, cts.Token)
.ContinueWith(t =>
{
if (t.IsCanceled)
{
"Cancelled".Dump();
}
else if (t.IsCompleted)
{
"Completed".Dump();
t.Result.Sum (r => r).Dump();
}
});
//sleep long enough to make sure the Task completes
Thread.Sleep(6000);
}
private IEnumerable<int> Test()
{
foreach(var i in Enumerable.Range(0, 10))
{
yield return i;
Task.Delay(500).Wait();
}
}
这表现——主要是——我所期望的:输出是“已完成”,然后是“45”。令我没想到的是,直到 Thread.Sleep() 调用完成后才输出“45”,而是立即输出了“Completed”。
所以我的问题是:如何立即评估我的任务的IsCompleted 标志,但直到调用线程从Thread.Sleep() 调用返回之后才评估Result 属性?此外,我有什么办法可以重组它,要么立即输出,要么都等待Sleep() 调用结束?
我知道这个例子是人为的,但我无法理解这种人为的行为。
编辑
附加问题:这种观察到的行为是否意味着我可能会进入任务的Result 属性在评估IsCompleted 和我能够评估Result 之间发生变化的状态?
编辑2
经过进一步调查,我能够回答我自己的一个问题:我可以通过更改 Test() 的行为来强制“完成”输出等到 Thread.Sleep() 完成后返回一个内置的 IList -在方法中而不是yield returning IEnumerable。我了解 IEnumerable 的一般工作原理,但我在这里看到的通过引入任务的行为让我很反感。
【问题讨论】:
标签: .net multithreading task-parallel-library c#-5.0