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