- Task.Run创建Task
- 另一种方式就是用TaskCompletionSource来创建Task
- TaskCompletionSource让你稍后开始和结束的任意操作中创建Task
- 它会为你提供一个可手动执行的“从属”Task
- 指示操作何时结束或发生故障
- 它会为你提供一个可手动执行的“从属”Task
- 它对IO-Bound类工作比较理想
- 可以获得所有Task的好处(传播值、异常、Continuation等)
- 不需要再操作的时候阻塞线程
使用TaskCompletionSource
- 初始化一个实例即可
- 它有一个Task属性可返回一个Task
- 该Task完全由TaskCompletionSource对象控制
- 调用任意一个方法都会给Task发信号:
- 完成、故障、取消
这些方法只能调用一次,如果再次调用:
- SetXxx会抛出异常
TryXxx会返回false
class Program
{
static void Main(string[] args)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() =>
{
Thread.Sleep(5000);
tcs.SetResult(42);
})
{
IsBackground = true
}.Start();
// 这行代码开始执行
Task<int> task = tcs.Task;
Console.WriteLine(task.Result);
Console.ReadLine();
}
}
自己实现类似于Task.Run方法
class Program
{
static void Main(string[] args)
{
Task<int> task = Run(() =>
{
Thread.Sleep(5000);
return 42;
});
Console.WriteLine(task.Result);
}
// 调用此方法相当于调用 Task.Factory.StartNew,
// 并使用 TaskCreationOptions.LongRunning 选项来创建非线程池的线程
static Task<TResult> Run<TResult>(Func<TResult> function)
{
var tcs = new TaskCompletionSource<TResult>();
new Thread(() =>
{
try
{
tcs.SetResult(function());
}
catch (Exception e)
{
tcs.SetException(e);
}
}).Start();
return tcs.Task;
}
}
TaskCompletionSource的真正魔力
它创建Task,但并不占用线程
public class Timer
{
static void Main(string[] args)
{
var awaiter = GetAnswerToLife().GetAwaiter();
awaiter.OnCompleted(() =>
{
Console.WriteLine(awaiter.GetResult());
});
Console.ReadLine();
}
static Task<int> GetAnswerToLife()
{
var tcs = new TaskCompletionSource<int>();
var timer = new System.Timers.Timer(5000) { AutoReset = false };
timer.Elapsed += delegate
{
timer.Dispose();
tcs.SetResult(42);
};
timer.Start();
return tcs.Task;
}
}
static void Main(string[] args)
{
Delay(5000).GetAwaiter().OnCompleted(() => Console.WriteLine(42));
// 5秒钟之后,Continuation 开始的时候,才占用线程
}
// 注意:没有非泛型版本的 TaskCompletionSource
static Task Delay(int milliseconds)
{
var tcs = new TaskCompletionSource<object>();
var timer = new System.Timers.Timer(milliseconds) {AutoReset = false};
timer.Elapsed += delegate
{
timer.Dispose();
tcs.SetResult(null);
};
timer.Start();
return tcs.Task;
}
}
Task.Delay相当于异步版本的Task.Sleep