.NET中的线程与异步(笔记)
翻出了之前记录的笔记,基本涵盖了.NET中线程和异步的相关概念。可以提供一个学习的方向。
线程类型
工作者线程
IO线程
线程池
全局队列(QueueUserWorkItem、Timer总是放入全局)
本地队列
工作者线程调度流程
如果本地队列有任务,则调度本地队列
如果本地队列没有任务则去其它工作者线程中调度
如果所有工作者线程本地队列都没有任务则去全局队列取任务调度
如果全局队列也没有任务则睡眠等待
如果睡眠了太长时间则自己醒来销毁自己
从全局队列取到本地队列采用 FIFO 算法
从本地队列取出时,采用 LIFO 算法
子任务、嵌套任务会被分配在线程的局部队列中
线程的开销
上下文切换
数据
AsyncLocal
ThreadLocal
ExecutionContext
SynchronizationContext(抽象的内容,基于ExecutionContext)
参考资料
https://blogs.msdn.microsoft.com/pfxteam/2012/06/15/executioncontext-vs-synchronizationcontext/
https://msdn.microsoft.com/en-us/magazine/gg598924.aspx
Timer
所有的Timer只有一个线程,调度具体任务时使用线程池
避免重复执行,使用Change方法
伪共享
因为不同的内核访问一个内核的cache发生的问题 [StructLayout(LayoutKind.Explicit)] [FieldOffset(64)]
异步模型
APM(异步编程模型)
BeginXXX、EndXXX
HTTP(RFC 2616) 客户端应用程序到一个服务器的并发连接数不应超过2个。
FCL强制了这个规则,除非重新指定"ServicePointManager.DefaultConnectionLimit"
FileStream
指定 FileOptions.Asynchronous 尽量使用 BeginRead,否则尽量使用Read章节:27.8.8
异步编程模型
线程同步
类库和线程安全
FCL法则
静态方法保证线程安全
实例方法不保证
基元用户模式和内核模式
用户模式
在硬件中发生
线程将一直在cpu上运行,称作“活锁”
内核模式
在操作系统中发生
windows会堵塞线程使它不再浪费cpu时间
线程将一直堵塞,称作“死锁”
windows操作系统检测不到一个线程在一个基元用户模式中构造上堵塞了。所以线程池不会创建一个新的线程来替换这种临时堵塞。
活锁浪费cpu时间和内存,死锁只浪费内存 同时使用称作:混合模式构造
用户模式构造
易失构造
它包含一个简单的数据类型的变量上执行原子性的读或写操作
互锁构造
它包含一个简单的数据类型的变量上执行原子性的读和写操作
相关FCL类型
1.Interlocked
2.SpinWait
3.SpinLock
内核模式构造
相关FCL类型
WaitHandle
EventWaitHandle
AutoResetEvent
ManualResetEvent
Semaphore
Mutex
混合模式构造
相关FCL类型
ManualResetEventSlim
SemaphoreSlim
CountdownEvent(与SemaphoreSlim相反) Monitor
Barrier(多线程协调)
lock Monitor
Task优势
- 任务使用的内存比线程少的多,创建和销毁所需的时间也少的多(复用线程)
- 线程池根据可用CPU数量自动伸缩任务规模
- 每个任务完成一个阶段后,运行的任务线程回到线程池,以便在那里接受新任务
- 线程池是站在整个进程的高度观察任务,所以,它能更好的调度这些任务,减少进程中的线程数,并减少上下文切换