1. 编译器到底对await做了什么
await 一个异步操作的时候,实际上编译器会创建一个状态机,这个状态机包含了调用者的上下文变量,状态机使用
yield
迭代器实现,状态机由clr调度,每次运行都会重新加入回队列,直到Task
完成或异常结束
2.Task有哪些实现方式
经常我们可以看到一些库中使用
TaskCompletionSource
来创建Task
,改变Task
的状态,实际上TaskCompletionSource
只是在Task基础上做简单的封装操作TaskCompletionSource
会直接创建一个Task
,设置Result
也是直接在Task
上设置结果,不同手动操作的地方就是做了自旋等待Task.IsCompleted
再返回,保证线程安全性
所以Task的实现
就是将Task
的状态切换补完的一个过程,让其成为一个Actor模型
,实现方式可以*发挥
3.clr到底怎么调度Task
所有的Task都是由
TaskScheduler
调度,最终进入到ThreadPool
队列中,然后clr获取队列中的工作项并运行Task.Wait()
操作会先将Task
移出TaskScheduler
然后再使用当前线程执行
TaskScheduler
有两种Scheduler
实现,默认是ThreadPoolTaskScheduler
Task.Run
将会在内部 new Task
创建一个任务,并将Task
添加到默认的TaskScheduler.Default
中TaskScheduler
默认是使用ThreadPoolTaskScheduler
实现
Task.Run
调用TaskScheduler.QueueTask
方法将Task添加到任务队列中,在ThreadPoolTashScheduler
中并没有保存任务队列,而是直接调用ThreadPool
中的UnsafeQueueCustomWorkItem
方法添加到ThreadPool
中,由ThreadPool
管理任务队列
ThreadPool
中有一个全局的工作队列,所有异步任务都将会加入到队列中,并由clr去获取队列中的IThreadPoolWorkItem
运行
ThreadPool
根据工作队列的数量,首先会先创建CPU核心数
数量的工作线程,并以每秒一个
的速度创建新线程
在ThreadPool
中,规定了任务的时间片,每个时间片为30个时钟
,每个线程运行满一个时间片才会返回线程池
CPU时钟使用Environment.TickCount
来计算