线程(thread)是操作系统能够进行运算调度的最小单位,也就是程序中的一个执行流。(其实可以分为操作系统内核调度的内核线程和用户空间调度的用户线程。在编程中我们创建的线程都是用户线程,本文中的线程是指用户线程,非内核线程)。
线程分为前台线程和后台线程。
clr中每个线程的建立都会分配到至少1M的内存空间,主要是线程中用户模式栈所占用。
在说道线程,就不得不说下进程的概念:
进程是操作系统中进行保护和资源分配的基本单位,操作系统分配资源以进程为基本单位。可以理解为每一个启动/运行的程序就是一个进程。
进程和线程的关系
一个进程至少包含一个线程(主线程),也可以是包含多个线程。
.Net中简单操作线程
1 public void TestThread() 2 { 3 int currentThreadId = Thread.CurrentThread.ManagedThreadId; ///当前线程的Id 4 5 ///创建Thread 6 var thread1 = new Thread(new ThreadStart(SendEmail)); 7 thread1.Start(); 8 var thread2 = new Thread(new ParameterizedThreadStart(SendMessage)); 9 thread2.Start("15933628754"); 10 11 //使用lambda构建 12 var thread3 = new Thread(p => SendEmail()); 13 thread3.Start(); 14 var thread4 = new Thread(p => SendMessage("52258844")); 15 thread4.Start(); 16 } 17 /// <summary> 18 /// 发送呢邮件 19 /// </summary> 20 private void SendEmail() 21 { 22 23 //TODO send email 24 Thread.Sleep(5000); //线程休眠5秒 25 Console.WriteLine("send the email completed"); 26 } 27 /// <summary> 28 /// 发送消息 29 /// </summary> 30 /// <param name="email"></param> 31 public void SendMessage(object email) 32 { 33 //TODO send message 34 }
Net中Thread提供操作的方法有
Start():启动线程;
Sleep(int):静态方法,暂停当前线程指定的毫秒数;
Abort():在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。调用此方法通常会终止线程。
Interrupt: 中断处于 Wait/Sleep/Join 线程状态的线程。
Join:在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止为止。此方法有不同的重载形式。
多线程是指程序(进程)中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务。
cpu的运行速度是非常快的,很多情况下都属于空闲状态。当程序仅适用单个线程去顺序处理业务时,对于一些相对庞杂的业务处理时,需要等待很久才可能执行完成。为了能够充分利用cpu资源,快速的处理业务,我们常常会将程序中创建多个线程来处理业务。
多线程的优势:
多线程的缺点:
总体而言,多线程的优势是非常明显的,特别是在处理高并发,业务复杂度比较庞杂的情况下尤为重要。而其缺点,我们可以根据代码进行控制,避免。
线程池是统一管理(创建,销毁,使用等)其创建线程的容器。
简单线程结构图
调用线程池处理任务的方法其实先将工作项放到全局队列中(注意这里不是存放在线程的本地队列中的,所以在取出任务时会涉及线程同步锁)。
由于是多个工作者线程在全局队列中拿走工作项,这就会形成并发情形,要有一个线程同步锁,保证两个或多个线程不会获取同一个工作项。这个线程同步锁在某些应用程序中可能成为瓶颈。工作者线程处理任务流程:
.Net中简单使用线程池示例
public void TestThreadPool() { #region 全局设置 //第一参数是设置线程池辅助线程,第二个值是设置异步I/O线程 // 异步 I/O 是用于处理I/O完成端口的线程。区别在于,系统如何为I/O操作和非I/O操作分配线程。 //当程序是I/O密集型时,你应该将线程数向I/O偏移,如果程序是CPU密集型时,则将线程数向工作线程偏移。 ThreadPool.SetMaxThreads(32, 32); ThreadPool.SetMinThreads(4, 4); #endregion //实际从接口中获取行情数据 var quotationInfo = new QuotationInfo() { Code = "Gold", CurrentPrice = 299.85m, Time = DateTime.Now, }; ThreadPool.QueueUserWorkItem(new WaitCallback(ManageQuotation), quotationInfo); } private void ManageQuotation(object quotation) { QuotationInfo quotationInfo = quotation as QuotationInfo; //TODO处理行情数据 }
线程池通过维护线程,使得线程可以重复利用,减少了频繁创建、回收线程导致的性能问题。但是使用线程池方法处理任务的缺点也非常明显
Task是.NET Framework 4.0才开始出现的。Task是为了更好的实现异步编程,Task提供了丰富的API来管理线程、控制执行顺序,获取执行结果等。它的本质是使用ThreadPool,但它的任务不是存放在线程池的全局队列中,而是存放在线程池的本地队列中,使线程之间的资源竞争减少(全局队列是加了线程同步锁的,而本地队列则没有)。
Task的简单代码
public void TaskTest() { Console.WriteLine("主线程Id " + Thread.CurrentThread.ManagedThreadId.ToString()); //创建task方式1:new Task(), 如果是有返回值的则使用 new Task<TResult>()。注意调用task.Start()才会启动 var task1 = new Task(() => { Task.Delay(100); Console.WriteLine("new Task() " + Thread.CurrentThread.ManagedThreadId.ToString()); }); task1.Start(); //方式2 Task.Run(),如果是有返回值的则使用 Task.Run<TResult>() Task.Run(() => { Task.Delay(10); Console.WriteLine("Task.Run " + Thread.CurrentThread.ManagedThreadId.ToString()); }); ///方式3 Task.Factory.StartNew() 如果是有返回值则调用Task.Factroy.Startnew<TResult>() Task.Factory.StartNew(() => { Task.Delay(10); Console.WriteLine("create by TaskFactory " + Thread.CurrentThread.ManagedThreadId.ToString()); }); }
async用于声明异步方法。await限定调用。
关于异步返回值:
调用异步方法简单流程
代码测试,注意Task.Delay(1000)方法。这是异步的等待,与Thread.Sleep是有区别的。因为Await Task.Delay,所以相当于需异步等待执行结果,也就是将任务插入线程池队列中,空闲的线程会消费这个任务。
public async void TaskTest() { Console.WriteLine("主线程Id "+Thread.CurrentThread.ManagedThreadId.ToString()); var task1 = new Task(() => { Console.WriteLine("task1 " + Thread.CurrentThread.ManagedThreadId.ToString()); }); task1.Start(); var xx=await ShowAsyncThread(); Console.WriteLine(xx); var taskl2 = Task.Factory.StartNew(()=> { Console.WriteLine("task2 "+Thread.CurrentThread.ManagedThreadId.ToString()); }); } private async Task<string> ShowAsyncThread() { Console.WriteLine("async "+Thread.CurrentThread.ManagedThreadId.ToString()); await Task.Delay(1000); await ShowAsyncThread2(); Console.WriteLine("async completed " + Thread.CurrentThread.ManagedThreadId.ToString()); return "xxx"; } private async Task<string> ShowAsyncThread2() { Console.WriteLine("async2 " + Thread.CurrentThread.ManagedThreadId.ToString()); await Task.Delay(1000); Console.WriteLine("async2 completed " + Thread.CurrentThread.ManagedThreadId.ToString()); return "xxx"; } }
结果
--------
以上
原文:https://www.cnblogs.com/johnyong/p/14089110.html