异步编程基础(01)

本章主要是用于讨论异步方式执行操作的各种方式。

1 线程池介绍
我们都知道,创建和销毁线程是一个非常昂贵的操作,需要耗费大量的时间,而且太多的线程也会浪费内存资源。在操作系统中必须调度可与性能的线程并执行上下文的切换,因此太多的线程性能也相应的会变差。
为了改善上面所提到的情况,微软在.NET Framework中提供了线程池的技术。线程池就是你的应用程序能使用的线程的集合。
在初始化阶段,线程池是没有线程的,而在线程池的内部维护了一个操作请求的队列。当我们需要执行一个异步操作时,就调用某个方法,将一个记录项追加到线程池的队列中,线程池的代码从这个队列中提取记录项,然后派发给一个线程池中的线程。如果线程池中没有线程,就会创建一个新的线程。
这个创建的线程创建并完成相应的任务之后,线程是不会销毁,而是返回到线程池中,并且该线程进入空闲的状态,等待响应新的请求。虽然线程的创建会损耗性能,但是由于线程不会销毁,所以不会再产生性能的损失。
当你的应用程序向线程池中发出许多请求,线程池会尝试用一个线程来处理该所有请求,如果请求的速度超过了线程池线程处理他们的速度,就会创建额外的线程。因此,应用程序的所有请求都是由少量线程处理,并不需要创建大量的线程。
如果你的应用程序停止了向线程池请求,线程池里面就会出现很多什么都不做的线程,这是一种资源浪费。因此,当一个线程池线程没有被请求一段时间后,线程会自己醒来并终止自己释放资源。
线程池可以容纳少量的线程,也可以容量更多的线程。线程池是启发式的。

2 线程池的简单操作
以下代码演示如何让一个线程池以异步的方式调用一个方法

public void ThreadPoolSample()
{
ThreadPool.QueueUserWorkItem((obj) =>
{
Console.WriteLine(obj);
Thread.Sleep(100);
});
Thread.Sleep(1000);
}

3 线程执行上下文

每一个线程都关联了一个执行上下文数据结构,执行上下文中包含的东西有安全设置、宿主设置、逻辑调用上下文数据。线程执行一些代码时,有些操作会受线程上下文的安全设置影响。在理想的情况下,每当一个初始线程使用另外一个辅助线程的时候,初始线程的上下文应该流向辅助线程,这样确保辅助线程执行的任何操作都是使用相同的安全设置和宿主设置。还确保了初始线程逻辑调用上下文数据可以适用于辅助线程。

默认情况下,初始线程的执行上下文流向任何辅助线程,这就造成了上下文信息传给辅助线程,会对性能产生一定的影响。因为执行的上下文中包含了大量的信息,将这些信息复制到辅助线程中,需要耗费不少的时间。为了解决这个问题在System.Threading中有个ExecutinonContext类,可以用来控制执行上下文从一个线程流向另外一个线程。

下列代码展示了如何阻止执行上下文的流动。

    public void SuppressFlow()
        {
            //将一些数据添加到该线程的逻辑调用上下文中
            CallContext.LogicalSetData("Name","Niko");
            ThreadPool.QueueUserWorkItem(state => { Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")); });
            //阻止线程执行上下文流动
            ExecutionContext.SuppressFlow();
            ThreadPool.QueueUserWorkItem(state => { Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")); });

            //恢复主线程的执行上下文流动
            ExecutionContext.RestoreFlow();

            Console.ReadLine();
        }

好了,今天的线程基础就到这里了,下一节我们将分析线程里面的《协作式取消和超时》。

原文地址:https://www.cnblogs.com/NikoMao/p/5956282.html