使用线程有几个缘由。假设从应用程序中进行网络调用须要必定的时间。咱们不但愿用户界面中止响应。让用户一直等待从服务器返回一个响应。用户同时执行其余一些操做,过着甚至取消发送给服务器的请求。这些均可以使用线程来实现。
对于全部的须要等待操做,列如,由于文件,数据库或网络访问都须要必定的时间,此时就能够启动一个新线程,同时完成其余任务。即便是处理密集型的任务,线程也是有帮助的。 一个进程的多线程能够同时在不一样CPU上运行,或多核CPU的不一样内核上。
若是多线程同时运行,访问相同的数据,就很容易出现问题,必须实现同步机制。
下面介绍的主要命名空间是:Syetem.Threading和System.Threading.Tasks数据库
线程是程序中独立的指令流。,
运行在服务器上的应用程序中,等待客户请求的线程,称为侦听器线程。 只要接受到请求,就把它传递给另外一个工做线程,以后继续与客户同行。侦听器线程会当即返回,接受下一个客户发送的下一个请求。
进程包含资源,每一个进程都分配了虚拟内存。一个进程至少包含一个线程。操做系统会调用线程。线程有一个优先级,实际上正在处理的程序的位置计数器,一个存储器局部变量的栈。每一个线程都有本身的栈,但程序代码的内存和堆由一个进程的全部线程共享。 这使一个进程的全部线程之间的通讯很是快–该进程的全部线程都寻址相同的虚拟内存。可是,这也使处理比较困难,由于多线程能够修改同一个内存位置。
线程是运行程序所必须的。在.NET4.0以前,必须直接使用Thread类和ThreadPool类。如今,.NET对着两个类作了抽象,容许使用Parallel类和Task类。
为编写可以利用并行性的代码,必须区分两种主要的场景:任务并行性和数据并行性。数组
Parallel类是对线程的一个很好的抽象。该类位于System.Threading.Tasks命名空间中,提供了数据和任务并行性
Parallel类定义了并行的for和foreach的静态方法。对于C#的for和foreach语句而言,循环从一个线程中运行。Parallel类使用多个任务,所以使用多个线程来完成做业。
Parallel.For()和Parallel.ForEach()方法在每次迭代中调用相同的代码,而Parallel.Invoke()方法容许同时调用不一样的方法。Parallel.Invoke用于任务并行性,而Parallel.ForEach用于数据并行性。服务器
ParallelLoopResult result = Parallel.For(0, 10, i => { Console.WriteLine("{0},task:{1},thread:{2}", i , Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); // Task.Delay(100);//是一个异步方法,用于释放线程供其余任务使用。 }); Console.WriteLine("IS complete:{0}", result.IsCompleted); Console.ReadKey();
程序的执行依次是:0-2-3-1-4-6-8-7-5-9;共有五个任务和五个线程。任务不必定映射到一个线程上,线程也能够被不一样的任务重用。markdown
在4.5中新增的Thread.Sleep方法,而不是Task.Delay方法。Task.Delay是一个异步方法,用于释放线程提供其余任务使用。下面代码使用await关键字,因此一旦延迟就会调用。网络
ParallelLoopResult asyncResult = Parallel.For(0, 10, async i => { Console.WriteLine("{0},task:{1},thread:{2}", i , Task.CurrentId, Thread.CurrentThread.ManagedThreadId); //使用await关键字,因此一旦完成延迟,就会当即调用这些代码 // 延迟后执行的代码和延迟前执行的代码能够运行不用的线程中 await Task.Delay(100); Console.WriteLine("{0},task:{1},thread:{2}", i , Task.CurrentId, Thread.CurrentThread.ManagedThreadId); }); Console.WriteLine("IS complete:{0}", asyncResult.IsCompleted); Console.ReadKey();
在代用Thread.Delay方法后,线程发生了变化。在输出中还能够看到,任务再也不存在,只有线程留下了,并且这里重用了前面的线程。另外一重要方面,Parallel类的For方法并无等待延迟,而是直接完成。Parallel类只等待它建立的任务,而不是等待其余后台活动。在延迟后,也有可能彻底看不到方法的输出,出现这种状况的缘由是主线程(前台线程)结束,全部的后台线程被终止。多线程
也能够提早中断Parallel.For()方法吗,而不是完成全部迭代。For()方法有一个重载接受Action异步
ParallelLoopResult asyncResult = Parallel.For(10, 40, async (int i,ParallelLoopState pls ) => { Console.WriteLine("{0},task:{1},thread:{2}", i , Task.CurrentId, Thread.CurrentThread.ManagedThreadId); //使用await关键字,因此一旦完成延迟,就会当即调用这些代码 // 延迟后执行的代码和延迟前执行的代码能够运行不用的线程中 await Task.Delay(10); if (i > 10) pls.Break(); //Console.WriteLine("{0},task:{1},thread:{2}", i // , Task.CurrentId, Thread.CurrentThread.ManagedThreadId); }); Console.WriteLine("IS complete:{0}", asyncResult.IsCompleted); Console.WriteLine("lowest break iteration :{0}", asyncResult.LowestBreakIteration); Console.ReadKey();
Parallel.ForEach()方法遍历实现了IEnumerable的集合,其方式相似于foreach语句,但以异步方法遍历。async
string[] data = { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "asss" }; ParallelLoopResult resule = Parallel.ForEach<string>(data, s => { Console.WriteLine(s); });
若是须要中断循环,使用ForEach()方法重载和ParallelLoopState 参数。
ForEach()方法重载:oop
public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource, ParallelLoopState, long> body)
实现代码以下:post
string[] data = { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "asss" }; ParallelLoopResult resule = Parallel.ForEach<string>(data,(s,pls,l) => { if (s.Contains("bbb")) pls.Break(); Console.WriteLine(s); Console.WriteLine( "LowestBreakIteration:" + pls.LowestBreakIteration); }); Console.ReadKey();
2.3经过Parallel.Invoke()方法调用多个方法
若是多个任务并行运行,就可使用parallel.Invoke()方法,它提供了任务并行模式。Parallel.Invoke()方法容许传递一个Action委托数组,在其中能够指定运行的方法。并行调用Foo和Bar方法
static void ParallelInvoke() { Parallel.Invoke(Foo,Bar); } static void Foo() { Console.WriteLine("foo"); } static void Bar() { Console.WriteLine("Bar"); }
Parallel类使用起来十分方便,并且可使用任务,已能够用于数据并行性。若是想要更细致的控制,而且不想等待Parallel类结束后才开始动做,就可使用Task类,固然,结合使用Task类和Parallel类也是能够的