c#异步编程基础

 

线程(Thread)

什么是线程Thread

  • 线程是一个可执行路径,它可以独立于其他线程执行.
  • 每个线程都在操作系统的进程(Process)内执行,而操作系统进程提供了程序运行的独立环境.
  • 单线程应用,在进程的独立环境里只跑一个线程,所以该线程拥有独占权.
  • 多线程应用,在单个进程中会跑多个线程,他们会共享当前的执行环境(尤其是内存) 

 

 

  线程的一些属性:

  • 线程一旦开始执行,IsAlive就是True,线程结束就变成false.
  • 线程结束的条件:线程构造函数传入的委托结束了执行.
  • 线程一旦结束,就无法重启.
  • 每个线程都有个Name属性,通常用于调试.线程Name只能设置一次,以后更改会抛出异常.
  • 静态的Tread.CurrentThread属性,会返回当前执行的线程.

 

  线程的Join and Sleep

  • 调用Join方法,就可以等待另一个线程结束.
  • 调用Join的时候,可以设置一个超时,用毫秒或者TimeSpan都可以.
    • 返回一个bool类型,如果返回true,那就是线程结束;如果返回false,那就表示超时了.
  • 调用Sleep方法会暂停当前的线程,并等待一段时间. 

    注意:

    • Thread.Sleep(0)这样调用会导致线程立即放弃当前的时间片,自动将CPU移交给其他的线程.
    • Thread.Yield()做同样的事情,但是它只会把执行交给同一处理器上的其他线程. 
    • 当等待Sleep或Join的时候,线程处于阻塞的状态.

 

  线程的阻塞

  • 如果线程的执行由于某种原因导致暂停,那么就认为该线程被阻塞了.例如在Sleep或通过Join等待其他线程结束.
  • 被阻塞的线程会立即将处理器的时间片生成给其他线程,从此就不再消耗处理器时间,直到满足其阻塞条件为止(然后cpu的时间片会返回到本线程).
  • 可以通过ThreadState这个属性来判断线程是否处于被阻塞的状态.
bool blocked=(someThread.ThreadState & ThreadState.WaitSleepJoin)!=0;

 

   ThreadState

  • ThreadState是一个flags enum,通过按位的形式,可以合并数据的选项.
  • 下图是Thread有可能处于的状态.但是它大部分的枚举值都没有什么用.四个最有用的值:Unstarted,Running,WaitSleepJoin和Stopped.

 

 

  解除阻塞Unblocking

  • 当遇到下列四种情况的时候,就会解除阻塞:
    • 阻塞条件被满足
    • 操作超时(如果设置超时的话)
    • 通过Thread.Interrupt()进行打断
    • 通过Thread.Abort()进行中止

 

  上下文切换

  • 当线程阻塞或解除阻塞时,操作系统将执行上下文切换.这会产生少量开销,通常为1或2微秒.

 

  I/O-bound vs Compute-bound(或CPU-Bound)

  • 一个花费大部分时间等待某事发生的操作称为I/O-bound
    • I/O绑定操作通常涉及输入或输出,但这不是硬性要求:Thread.Sleep()也被视为I/O-bound
  • 相反,一个花费大部分时间执行CPU密集型工作的操作称为Compute-bound

   

  阻塞 vs 忙等待(自旋)

  Blocking vs Spinning

  • I/O-bound操作的工作方式有两种:
    • 在当前线程上同步的等待
      • Console.Readline(),Thread.Sleep(),Thread.Join()...
    • 异步的操作,在稍后操作完成时触发一个回调动作.
  • 同步等待的I/O-bound操作将大部分时间花在阻塞线程上.
  • 他们也可以周期性的在一个循环里进行"打转(自旋)"
while(DateTime.Now<nextStartTime)
    Thread.Sleep(100);

while(DateTime.Now<nextStartTime)
  • 在忙等待和阻塞方面有一些细微的差别
    • 首先,如果你希望条件很快得到满足(可能在几微秒之内),则短暂的自旋可能会很有效,因为它避免了上下文切换的开销和延迟.
      • .NET Framework提供了特殊的方法和类来提供帮助SpinLock和SpinWait
    • 其次,阻塞也不是零成本.这是因为每个线程在生存期间会占用大约1MB的内存,并会给CLR和操作系统带来持续的管理开销.
      • 因此,在需要处理成百上千个并发操作的大量I/O-bound程序的上下文中,阻塞可能会很麻烦
      • 所以,此类程序需要使用基于回调的方法,在等待时完全撤销其线程              

                 

 

 

posted @ 2020-11-24 20:34  熙熙_攘攘  阅读(101)  评论(0)    收藏  举报