C#中的线程简介
为什么要使用线程
- 同一时间智能运行一个任务,长时间运行的任务独占整个计算机,造成其他程序无法响应。
- 如果程序有bug会造成整个机器停止工作,用户只好重启计算机,造成数据丢失。
于是,人们为操作系统引入了线程的概念。线程就是对CPU的虚拟化。一个线程就是一个逻辑上的CPU。物理上的CPU会按照调度执行每个线程上的指令。当一个线程出现问题时,也不会影响到其他的线程。
这样,整个操作系统就更加健壮、易于伸缩和安全了。在安装了多个CPU的机器上,计算机是可以真正的同时运行多个线程的,这由操作系统进行保证。
线程的代价
- 线程需要占用内存空间
- 线程切换也会增加额外的CUP计算时间
- 线程的创建和销毁需要消耗大量时间
.Net中使用线程的方法
- 定义两个方法模拟耗时的操作
public static void Work1()
{
Console.WriteLine($"Work1 开始 id:{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 25; i++)
{
Console.WriteLine($"Work2 {i}");
Thread.Sleep(10);
}
Console.WriteLine($"Work1 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
public static int Work2()
{
Console.WriteLine($"Work2 开始 id:{Thread.CurrentThread.ManagedThreadId}");
int count = 0;
for (int i = 0; i < 100; i++)
{
Console.WriteLine($"Work1 {i}");
Thread.Sleep(10);
count += 1;
}
Console.WriteLine($"Work2 结束 id:{Thread.CurrentThread.ManagedThreadId}");
return count;
}
- 使用Thread执行两个方法
public static void UseThread()
{
Console.WriteLine($"UseThread 开始 id:{Thread.CurrentThread.ManagedThreadId}");
Thread thread1 = new(Work1);//创建一个线程
thread1.Start();//启动线程
Thread thread2 = new(() => Work2());//由于Work2有返回值,用一个Lambda表达式包装后传入
thread2.Start();
Console.WriteLine($"UseThread 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
- 为了减少创建和销毁线程的开销,可以使用ThreadPool(线程池),它可以复用线程,从而提高了效率。
public static void UseThreadPool()
{
Console.WriteLine($"UseThreadPool 开始 id:{Thread.CurrentThread.ManagedThreadId}");
ThreadPool.QueueUserWorkItem(t => Work1());
ThreadPool.QueueUserWorkItem(t => Work2());
Console.WriteLine($"UseThreadPool 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
- 直接使用线程执行任务时,在处理任务结果获取、线程取消、多线程任务协调等场景时,显得非常笨拙。于是在线程池的基础上,.Net推出了Task
public static void UseTask()
{
Console.WriteLine($"UseTask 开始 id:{Thread.CurrentThread.ManagedThreadId}");
Task task1 = new(Work1);
task1.Start();
Task task2 = new(() => Work2());
task2.Start();
//上面跟直接使用Thread类似
//下面也可以用TaskFactory启动任务
//Task.Factory.StartNew(Work1);
//Task.Factory.StartNew(() => Work2());
Console.WriteLine($"UseTask 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
- 以上看起来跟使用Thread没什么差别,下面我们来看看使用Task的便利之处
//等待任务执行完成
public static void UseTaskWait()
{
Console.WriteLine($"UseTaskWait 开始 id:{Thread.CurrentThread.ManagedThreadId}");
var task1 = Task.Factory.StartNew(Work1);
var task2 = Task.Factory.StartNew(() => Work2());
//Task.WaitAll(task1,task2);//两个任务都执行完成后,才继续执行后面的代码
Task.WaitAny(task1, task2);//两个任务任何一个完成,就继续执行后面的代码
Console.WriteLine($"UseTaskWait 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
//任务执行完成后执行ContinueWith内的代码,并获得了返回值
public static void UseTaskContinueWith()
{
Console.WriteLine($"UseTaskContinueWith 开始 id:{Thread.CurrentThread.ManagedThreadId}");
Task.Run(Work1);
//此方法会异步执行,ContinueWith中传入回调函数,用于处理Work2返回的结果
Task.Run(Work2).ContinueWith(r =>
{
Console.WriteLine($"Work2 result {r.Result}");
});
Console.WriteLine($"UseTaskContinueWith 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
//获取任务的执行结果
public static void UseTaskResult()
{
Console.WriteLine($"UseTaskResult 开始 id:{Thread.CurrentThread.ManagedThreadId}");
var task2 = Task.Run(Work2);
task2.Wait();//这里会阻塞,等待task2执行完毕
Console.WriteLine($"task2's result:{task2.Result}");
//或者直接这样写
//var result = task2.Result;//这里会阻塞,等待task2执行完毕
//Console.WriteLine($"task2's result:{result}");
Console.WriteLine($"UseTaskResult 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
- 为了使用更方便,.Net上引入了async/await关键字,于是我们可以这样使用
public static async void CallMethodAsync1()
{
Console.WriteLine($"CallMethodAsync1 开始 id:{Thread.CurrentThread.ManagedThreadId}");
var result = await Task.Run(Work2);
Console.WriteLine($"result:{result}");
Console.WriteLine($"CallMethodAsync1 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
如果任务本身就是异步的
public static Task<int> Work3()
{
Console.WriteLine($"Work3 开始 id:{Thread.CurrentThread.ManagedThreadId}");
var result = Task.Run(() =>
{
int count = 0;
for (int i = 0; i < 100; i++)
{
Console.WriteLine($"Work1 {i}");
Thread.Sleep(10);
count += 1;
}
return count;
});
Console.WriteLine($"Work3 结束 id:{Thread.CurrentThread.ManagedThreadId}");
return result;
}
//可以这样调用,有同样的效果
public static async void CallMethodAsync2()
{
Console.WriteLine($"CallMethodAsync2 开始 id:{Thread.CurrentThread.ManagedThreadId}");
var result = await Work3();
Console.WriteLine($"result:{result}");
Console.WriteLine($"CallMethodAsync2 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
标签:Console,CurrentThread,Thread,C#,简介,线程,WriteLine,id
From: https://www.cnblogs.com/higleam/p/18039965