引言
在编程的世界里,并发编程无疑是提升性能和效率的重要手段。本文将带你从进程、线程的基本概念出发,逐步深入到线程池、Task类以及await和async的使用,让你全面理解并发编程的精髓。
一、基本概念
1. 进程(Process)
进程是计算机中的一个执行中的程序,它是对运行程序的抽象。进程包括程序的代码、数据、堆栈以及其他操作系统所需的资源。每个程序运行时至少会开启一个进程。
2. 线程(Thread)
线程是程序中的一个执行流,每个线程都有自己的寄存器(栈指针、程序计数器等),但代码区是共享的。每个进程至少拥有一个线程,称为主线程,其他线程统称为子线程。如果线程数量超过2,则称为多线程编程。
3. 协程(Coroutine,Python中的yield)
协程是一种更轻量级的线程,它允许在函数执行过程中进行挂起和恢复,从而实现更高效的并发。
4. 句柄(Handle)
句柄是Windows系统对象或实例的标识,这些对象包括程序实例、窗口、位图、资源、文件等。
二、概念的区别
- 进程:类比火车站,占用大量资源,但能大幅提升效率。
- 线程:类比售票窗口,窗口只能在火车站用,占用中等资源,同样能大幅提升效率。
- 协程:类比售票员,更轻量级,实现更高效的并发。
三、Thread类详解
1. 实例化线程
- 直接传入方法名称:
Thread t = new Thread(Hello); t.Start();
- 通过ThreadStart:
ThreadStart ts = new ThreadStart(Hello); Thread t = new Thread(ts); t.Start();
- 通过ParameterizedThreadStart(必须传参数):
static void Hello(object)
2. 启动线程
t.Start();
3. 其他方法
t.Abort()
: 终止线程(不推荐使用)t.Suspend()
: 挂起线程(已被废弃)t.Resume()
: 继续已挂起的线程(已被废弃)
4. 常用属性
Thread.CurrentThread
: 当前线程Thread.CurrentThread.Name
: 线程名称Thread.CurrentThread.ManagedThreadId
: 线程编号t.IsBackground = true;
: 是否为后台线程。false表示前台线程,界面关闭后等待其他线程执行完再关闭;true表示后台线程,界面关闭时线程随之结束。t.Priority
: 线程优先级(Lowest、BelowNormal、Normal、AboveNormal、Highest)
5. 线程的同步
线程同步指的是某一时刻只允许有一个线程访问变量。如果不能保证变量的访问是同步的,会产生错误。解决方案是加锁,使用lock()
关键字。
四、线程池
线程池是由系统自动维护的一个资源组,我们只需从池中取出相应的资源进行使用。使用线程池可以避免频繁开启和销毁线程带来的资源浪费。
五、Task类(官方推荐)
1. 实例化
new Task()
: 使用Action或Func委托实例化Task。Task.Run()
: 简化的Task实例化方法,自动执行无需start。TaskFactory
: 使用TaskFactory来创建和启动任务。task.RunSynchronously()
: 同步方式执行任务。
2. 线程等待
task.Wait()
: 等待线程的代码执行完再向下执行。Task.WaitAny()
: 等待任务集合中的任意一个任务完成。Task.WaitAll()
: 等待任务集合中的所有任务完成。Task.WhenAny()
和Task.WhenAll()
: 分别用于在任意一个或多个任务完成时执行后续操作。
六、await和async(高级话题)
async:异步方法的关键字。
await:用于等待异步方法完成。
用法:
async
写在定义的方法前。async
必须和await
一起使用,否则方法是同步的。
示例:
static async void Hello()
{
Console.WriteLine("Hello");
}
七、Parallel并行循环
串行、并行、同步、异步、并发 是并发编程中的基本概念。
Parallel.For 和 Parallel.ForEach:
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 4; // 设置最大并行度为4
Parallel.For(0, 100, options, (int num) =>
{
Console.WriteLine($"Processing {num} on thread {Task.CurrentId}");
// 模拟一些工作
System.Threading.Thread.Sleep(100);
});
Console.WriteLine("All tasks completed.");
}
}
更改线程数量:
使用 ParallelOptions
类来设置最大并行度。
八、实战案例
案例:请循环运行10万次,生成1-100万个数字,存放到列表中。代码执行完后打印列表的元素个数。
回答方向:
- 异步(Thread、ThreadPool、Task等)。
- 为了防止资源抢夺,使用线程同步(加锁或安全类型)。
- 使用Task类来实现。
- 使用await、async技术(虽然不太熟练,但值得学习)。
结语
并发编程是一个复杂而强大的工具,它能帮助我们提升程序的性能和效率。从进程、线程到Task类,再到await和async的使用,每一步都充满了挑战和机遇。希望本文能帮助你更好地理解并发编程,并在实际项目中灵活运用这些技术。