第二十六章 计算限制的异步操作

多线程涉及到很多知识和技巧…

1.线程

创建线程是有较大的开销的,每个线程都会占用一定的内存Windows为每个线程的用户模式分配1M的内存,分配24K的内科模式栈,虽然线程可能不运行,切换线程也是有代价的,需要切换线程上下文.

2. CLR线程池

每个CLR拥有一个线程池.线程池维护线程用来执行用户的异步操作请求.创建一个线程并使用结束之后,线程不会立即销毁,而是返回线程池,等待下一次调用,如果长时间没有用才会自己销毁.类似资源池.两个任务可能使用的是一个线程.

3. 执行上下文

每个线程都关联了一个执行上下文数据,线程执行代码时,有些操作会受到线程的执行上下文的设置的影响.

默认情况下,初始线程的执行上下文会流向辅助线程,但是会造成一定的性能影响.

ExecutionContext类允许控制线程的执行上下文如何流向另一个线程.

4. 协作式取消

如果需要长时间运行的计算限制操作需要运行的过程中取消,可以创建一个CancellationTokenSource通知 System.Threading.CancellationToken,告知其应被取消.将CancellationTokenSource.Token传递到开辟的线程中,在新线程中检测token.lsCancelationResuested属性,如果在主线程中调用了Cancel方法,新线程就可以检测到lsCancelationResuested属性的变化.

    var cts = new CancellationTokenSource();

    ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));

    Thread.Sleep(1000);
    Console.WriteLine("Press ENTER to stop");
    Console.ReadLine();
    cts.Cancel();
    Console.ReadLine();
}

private static void Count(CancellationToken token, int countTo)
{
    for (int i = 0; i < countTo; i++) {
        if (token.IsCancellationRequested) {
            Console.WriteLine("token.IsCancellationRequested Called");
            break;
        }
        Console.WriteLine(i);
        Thread.Sleep(200);
    }
}

cts.Token.Register 注册一个将在取消此 System.Threading.CancellationToken 时调用的委托

5. 任务Task

ThreadPool.QueueUserWorkItem创建一个异步的受计算限制的的操作是非常简单的,但是不知道操作什么时候完成.Task可以实现这样的效果.

task.Wait()方法,等待 System.Threading.Tasks.Task 完成执行过程.Result获取方法的返回值.

Task当然也可以使用CancellationTokenSource进行操作的取消.

Result 如果任务还没有结束,就调用Result获取结果,在内部会调用Wait方法,导致线程阻塞.

task.ContinueWith 创建一个在目标 System.Threading.Tasks.Task 完成时执行的延续任务.

TaskContinuationOptions  为通过使用 System.Threading.Tasks.Task.ContinueWith方法创建的任务指定行为.可以指定什么情况下才执行Continue线程.

子线程还可以创建子线程并设置TaskContinuationOptions  为AttachedToParent,那么新的子线程也会作为子线程的一部分,”算是同级了”.

如果希望多个Task共享一些设置和传入的参数可以创建TaskFactory或TaskFactory<>.由TaskFactory创建的Task都共享这些设置.

6. Parallel的静态For,ForEach和Invoke方法

如果循环当中的操作可以并行,而且没有修改共享数据,可以使用Parallel的这几个方法,这些方法内部会调用线程参与处理.

7. 并行语言集成查询(PLINQ)

System.Linq.ParallelEnumerable类实现了这些功能.

一般的Linq查询是一个线程顺序处理查询数据,为了提高性能可以使用并行Linq,将集合中的数据项的处理分散到多个CPU上,以便并发处理多个数据项.当然,这里有线程同步的性能影响.

8.线程注意事项

System.Timers.Timer是System.Threading.Timer的包装类.与设计平面相关的时候可以使用,别的情况下,尽量不要使用.

尽量不要手工设置线程池的最大线程数.

原文地址:https://www.cnblogs.com/zhangliming/p/3508595.html