不可不知的C#基础 3. 线程浅析
线程可以使你的项目运行得更加的流畅.
什么是线程呢?
线程(thread)是程序执行流的最小单元, 是程序中一个单一的顺序控制流程. 每个程序最少有一个线程, 那就是程序本身.
在C#中, 你可以使用 System.Threading 提供的类,接口和方法实现线程的所有操作.
单线程操作
想象着你走进快餐店, 大叫一声"来碗兰州拉面", 然后就坐在饭桌上等. 当厨师听到你的要求时,他就开始做兰州拉面了. 理论上讲, 当你叫了以后, 厨师就已经收到了命令.
用代码可以这样表达:
static void Main(string[] args)
{
string name = "兰州拉面";
Console.WriteLine("来碗" + name);
PlaceOrder(name);
Console.WriteLine("坐在饭桌上....");
Console.Read();
}
static void PlaceOrder(string name)
{
Console.WriteLine("开始制作" + name);
}
static void PlaceOrder(string name)
{
Thread thread1 = new Thread(new ThreadStart(Cooking));
thread1.Start();
}
static void Cooking()
{
Console.Write("开始制作");
}
运行程序, 你会发现输出结果是:
这是表示虽然厨师听到你的声音了,但是你坐在饭桌上的动作是在他开始做拉面之前. -- 更加的合情合理, 是吗?
我们还可以引入参数:
static void PlaceOrder(string name)
{
Thread thread1 = new Thread(t => Cooking(name));
thread1.Start();
}
static void Cooking(string name)
{
Console.WriteLine("开始制作" + name);
}
注意上面的参数的传递方法只用于.net 3.5/4
多线程
如果一个饭店有多个厨师, 并且同时有多个人点餐, 我们可以像这样模拟实现:
static void Main(string[] args)
{
string name = "兰州拉面";
int number = 5;
Console.WriteLine("来" + number + "碗" + name);
PlaceOrder(name, 5);
Console.WriteLine("坐在饭桌上....");
Console.Read();
}
static void PlaceOrder(string name, int number)
{
for (int i = 0; i < number; i++)
{
Thread thread1 = new Thread(t => Cooking(name));
thread1.Start();
}
}
static void Cooking(string name)
{
Console.WriteLine("开始制作" + name);
}
运行后, 结果显示:
嗯, 有些厨师动作还是快得像机器人, 让我们给他们一些休息的时间:
static void Cooking(string name)
{
Thread.Sleep(10);
Console.WriteLine("开始制作" + name);
}
再次运行程序, 结果是:
线程的关联性和独立性
线程的运作是相对独立的, 完成不同的工作. 但是它们却是共享进程内的资源.
做个实验:
static void PlaceOrder(string name, int number)
{
int[] array = new int[] {1000,500,300,500,1};
for (int i = 0; i < number; i++)
{
int time = array[i];
Thread thread1 = new Thread(t => Cooking(name, i,time));
thread1.Start();
}
}
static void Cooking(string name, int id, int time)
{
Thread.Sleep(10);
Console.WriteLine(id + "号开始制作" + name);
}
这里我们想给每一个厨师一个编号, 但是当把i 当中参数传递的时候, visual studio 会发出警告:
" Access To Modified Closure “.
这个是什么意思呢? 运行一下程序, 输出是:
发现在运行程序的时候, 错误的读取了厨师的编号, 这就是那个警告发出的原因: 因为线程们共享的名字 i 在不停的变化中, 我们没有办法控制一个特定线程运行时i 的值, -- 它们是相对独立的.
解决方案就是增加一个变量名存放值作为传递:
static void PlaceOrder(string name, int number)
{
int[] array = new int[] {1000,500,300,500,1};
for (int i = 0; i < number; i++)
{
int j = i;
int time = array[i];
Thread thread1 = new Thread(t => Cooking(name, j,time));
thread1.Start();
}
}
static void PlaceOrder(string name, int number)
{
int[] array = new int[] {1000,500,300,500,1};
for (int i = 0; i < number; i++)
{
int j = i;
int time = array[i];
Thread thread1 = new Thread(t => Cooking(name, j,time));
thread1.Start();
}
}
static void Cooking(string name, int id, int time)
{
Thread.Sleep(10);
Console.WriteLine(id + "号开始制作" + name);
Thread.Sleep(time);
Console.WriteLine(id + "号准备完毕,花费时间:" + time);
}
请仔细读读上面的代码和输出的结果, 应该大家都可以理解.
本文来自于喜乐的ASP.NET(Alex Song) 转贴请注明出处
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库