目录
6、Task中专门的异常处理AggregateException
前言
Q1:为什么要使用线程?
在多CPU和多核时代,使用线程能够充分利用硬件资源,提升软件的运行效率。但是没有章法的乱用线程会适得其反。
Q2:线程和进程关系?
一个程序运行,通常在任务管理器中看到一个进程。这个进程占用多少资源,并不是由进程本身决定。而是由这个进程分配 的线程决定。也就是说操作系统是通过线程来管理程序资源的。
一、异步线程
异步线程是一种用于处理耗时操作的机制,它允许应用程序在执行某些操作时不被阻塞,以提高性能和响应性.
使用async和await关键字
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
Console.WriteLine("开始执行异步操作");
await ExecuteAsyncOperation(); // 调用异步方法,并在此等待其完成
Console.WriteLine("异步操作完成");
}
public static async Task ExecuteAsyncOperation()
{
Console.WriteLine("开始执行异步操作");
// 模拟一个耗时的操作,这里使用 Task.Delay 方法来模拟
// 这个操作会暂停方法的执行,但不会阻塞主线程
await Task.Delay(1000); // 暂停 1 秒钟
Console.WriteLine("异步操作完成");
}
}
基于委托实现
调用BeginInvoke()方法
利用返回结果状态做进度条
异步等待WaitOne
异步返回值EndInvoke
二、同步线程
同步线程是指线程的执行是按照顺序的,每个操作都必须等待前一个操作完成后才能继续执行,这种线程模型被称为同步。
三、Thread线程
开启线程
设置线程优先级
thread.Priority=ThreadPriority.Highest;//设置高优先级,只是一个概率的提升
Thread拓展封装
场景一:开启新线程执行任务后紧接着需要执行的一个任务
场景二:开启一个线程,既要不卡界面,又要返回结果
Func<int> func=()=>
{
Thread.Sleep(2000);
return 6;
};
Fun<int> funcResult=ThreadWithReturn(func);
int iResult=funcResult.Invoke();//如果需要执行结果,等待是必须的
四、ThreadPool线程池
线程池是一个用于管理和重用线程的机制,它提供了一种轻量级的方式来处理并发执行的任务。线程池在应用程序启动时会创建一组预分配的线程,这些线程被放置在线程池中,并准备好处理工作项。当应用程序需要执行某个任务时,可以将任务提交给线程池,并由线程池中的线程来执行任务。使用线程池的好处之一是可以减少线程创建和销毁的开销,因为线程池会重用已创建的线程,从而提高性能和资源利用率。
注:线程池是一个共享的资源,因此需要注意使用线程池的任务应尽量是短期的,以避免阻塞线程池中的其他任务。如果需要执行长时间运行的任务,可以考虑使用Async/Await或其他异步编程模型。
常规使用
1)ThreadPool.QueueUserWorkItem
运行结果:方法1、2中的任务是由线程池自动调度的
2)一些使用示例
设置线程数
线程等待
Thread和ThreadPool比较
【1】Thread:只要我们需要异步任务,都会开启一个Thread,比然有时间和空间开销。
【2】TheadPool:是一个线程池,由系统维护和缓存,因为默认都是初始化好的,所以使用方便,退回容易。用的时候,只需要请求即可。
Thread开启10个线程
ThreadPool开启10个线程
总结:
【1】我们的线程池可以根据电脑的实际CPU情况开启一定个数的线程,放到线程池中。
【2】10个异步任务,但是我们通过4个线程就完成了,节省时间和空间开销。
通过线程池做一些扩展(定时器类)
五、Task线程(推荐使用)
Task是一种用于多线程编程的高级概念。Task可以把工作项分配给线程执行,使得你可以轻松地编写异步代码。
在C# 5.0以前,编写异步代码需要使用回调函数或Thread类等底层API,这使得代码复杂难以维护。而在C# 5.0引入async/await语法之后,使用Task来编写异步代码变得更加简单和直观,使用Task来编写异步代码的好处之一是可以避免使用回调函数,使得代码更加简洁和易于维护。同时,Task还提供了其他高级的功能,如取消异步操作和处理多个异步操作的结果等。
1、常规使用
new一个新的Task
例子
运行结果