C# 多线程与异步的使用方法笔记
本帖最后由 Cool_Breeze 于 2021-5-16 10:32 编辑认真阅读这句话:请务必 将任务理解为工作的异步抽象,而非 在线程之上的抽象。 默认情况下,任务在当前线程上执行,且在适当时会将工作委托给操作系统。 可选择性地通过 Task.Run API显式请求任务在独立线程上运行。
# 线程与异步的使用方法
## 使用场景
1. **方法** **AAA, BBB, CCC**
2. 在主线程不阻塞的情况下运行不同的三个方法
3. 方法**CCC**需要在方法**AAA**完成后执行
## 使用线程完成
因为方法 **CCC** 要等待方法 **AAA** 完成,所以需要一个线程同步事件。
```c#
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static EventWaitHandle CCClcok = new EventWaitHandle(false, EventResetMode.ManualReset);
static void Main()
{
Thread tha = new Thread(AAA);
Thread thb = new Thread(BBB);
Thread thc = new Thread(CCC);
tha.Start();
thb.Start();
thc.Start();
Console.WriteLine("等待所有任务完成!");
}
static void AAA()
{
int sec = 10;
while (sec >= 1)
{
Console.WriteLine("方法 AAA: {0} 秒", sec);
sec--;
Thread.Sleep(1000);
}
Console.WriteLine("方法 AAA 执行完成!");
CCClcok.Set();
}
static void BBB()
{
int sec = 5;
while (sec >= 1)
{
Console.WriteLine("方法 BBB: {0} 秒", sec);
sec--;
Thread.Sleep(1000);
}
}
static void CCC()
{
CCClcok.WaitOne();
int sec = 3;
while (sec >= 1)
{
Console.WriteLine("方法 CCC: {0} 秒", sec);
sec--;
Thread.Sleep(1000);
}
}
}
```
### 线程同步事件
**false** 表示事件为非终止状态,**EventResetMode.ManualReset** 表示手动重置此事件((https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.eventwaithandle?view=netframework-4.8))
```c#
static EventWaitHandle CCClcok = new EventWaitHandle(false, EventResetMode.ManualReset);
```
### 方法 AAA
**CCClcok.Set()** 将事件状态设为终止。被阻塞线程继续 ((https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.eventwaithandle.set?view=netframework-4.8#System_Threading_EventWaitHandle_Set))
```c#
static void AAA()
{
int sec = 10;
while (sec >= 1)
{
Console.WriteLine("方法 AAA: {0} 秒", sec);
sec--;
Thread.Sleep(1000);
}
Console.WriteLine("方法 AAA 执行完成!");
CCClcok.Set();
}
```
### 方法 BBB
无要求
```c#
static void BBB()
{
int sec = 5;
while (sec >= 1)
{
Console.WriteLine("方法 BBB: {0} 秒", sec);
sec--;
Thread.Sleep(1000);
}
}
```
### 方法 CCC
**CCClcok.WaitOne()** 阻止当前线程,直到当前 (https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.waithandle?view=netframework-4.8) 收到信号。(继承自 (https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.waithandle?view=netframework-4.8))[^ 1 ]
[^ 1 ]: 如果方法 AAA 没有执行 CCClcok.Set() 这里会出现死锁
```c#
static void CCC()
{
CCClcok.WaitOne();
int sec = 3;
while (sec >= 1)
{
Console.WriteLine("方法 CCC: {0} 秒", sec);
sec--;
Thread.Sleep(1000);
}
}
```
### Main函数
线程默认为前台线程((https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.thread.isbackground?view=netframework-4.8)),所有主线程会等待所有子线程结束 ((https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.thread?view=netframework-4.8))
```c#
static void Main()
{
Thread tha = new Thread(AAA);
Thread thb = new Thread(BBB);
Thread thc = new Thread(CCC);
tha.Start();
thb.Start();
thc.Start();
Console.WriteLine("等待所有任务完成!");
}
```
### 执行结果
```powershell
Microsoft (R) Visual C# Compiler version 4.8.3761.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reser
This compiler is provided as part of the Microsoft (R
方法 AAA: 10 秒
方法 BBB: 5 秒
等待所有任务完成!
方法 BBB: 4 秒
方法 AAA: 9 秒
方法 BBB: 3 秒
方法 AAA: 8 秒
方法 AAA: 7 秒
方法 BBB: 2 秒
方法 BBB: 1 秒
方法 AAA: 6 秒
方法 AAA: 5 秒
方法 AAA: 4 秒
方法 AAA: 3 秒
方法 AAA: 2 秒
方法 AAA: 1 秒
方法 AAA 执行完成!
方法 CCC: 3 秒
方法 CCC: 2 秒
方法 CCC: 1 秒
请按任意键继续. . .
```
## 使用异步完成
- 注意事项((https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/async),(https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/await))
1. **async** 方法内部没有 **await** 关键字将以同步方法运行
2. **await** 必须出现在 **async** 方法内部
3. **await** 接一个异步对象(必须是可等待的)
- 不能让主线程直接退出,无法查看后面运行结果!
```c#
Thread.Sleep(14000);
```
```c#
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
BBB();
CCC();
Console.WriteLine("等待所有任务完成!");
Thread.Sleep(14000);
}
static async Task AAA()
{
int sec = 10;
while (sec >= 1)
{
Console.WriteLine("方法 AAA: {0} 秒", sec);
sec--;
await Task.Delay(1000);
}
Console.WriteLine("方法 AAA 执行完成!");
}
static async void BBB()
{
int sec = 5;
while (sec >= 1)
{
Console.WriteLine("方法 BBB: {0} 秒", sec);
sec--;
await Task.Delay(1000);
}
}
static async void CCC()
{
await AAA();
int sec = 3;
while (sec >= 1)
{
Console.WriteLine("方法 CCC: {0} 秒", sec);
sec--;
await Task.Delay(1000);
}
}
}
```
### 方法 AAA
返回一个 **Task** 对象
```c#
static async Task AAA()
{
int sec = 10;
while (sec >= 1)
{
Console.WriteLine("方法 AAA: {0} 秒", sec);
sec--;
await Task.Delay(1000);
}
Console.WriteLine("方法 AAA 执行完成!");
}
```
### 方法 BBB
无需等待,可以不用返回 **Task** 对象
```c#
static async void BBB()
{
int sec = 5;
while (sec >= 1)
{
Console.WriteLine("方法 BBB: {0} 秒", sec);
sec--;
await Task.Delay(1000);
}
}
```
### 方法 CCC
无需等待,可以不用返回 **Task** 对象
使用 **await** 等待方法 **AAA** 执行完毕
```c#
static async void CCC()
{
await AAA();
int sec = 3;
while (sec >= 1)
{
Console.WriteLine("方法 CCC: {0} 秒", sec);
sec--;
await Task.Delay(1000);
}
}
```
### 执行结果
```powershell
Microsoft (R) Visual C# Compiler version 4.8.3761
for C# 5
Copyright (C) Microsoft Corporation. All rights r
This compiler is provided as part of the Microsof
方法 BBB: 5 秒
方法 AAA: 10 秒
等待所有任务完成!
方法 BBB: 4 秒
方法 AAA: 9 秒
方法 BBB: 3 秒
方法 AAA: 8 秒
方法 BBB: 2 秒
方法 AAA: 7 秒
方法 BBB: 1 秒
方法 AAA: 6 秒
方法 AAA: 5 秒
方法 AAA: 4 秒
方法 AAA: 3 秒
方法 AAA: 2 秒
方法 AAA: 1 秒
方法 AAA 执行完成!
方法 CCC: 3 秒
方法 CCC: 2 秒
方法 CCC: 1 秒
请按任意键继续. . .
``` 本帖最后由 Cool_Breeze 于 2021-5-16 10:21 编辑
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static Task task;
static void Main()
{
Task.WaitAll(ShowTimeMain(),MonitorShowTimeStatus());
}
static async Task ShowTimeMain()
{
task = ShowTime();
await task;
}
static async Task ShowTime()
{
await Task.Factory.StartNew
(
() =>
{
int n = 10;
while (n >= 0)
{
Console.WriteLine(DateTime.Now);
Thread.Sleep(1000);
n--;
}
}
);
}
static async Task MonitorShowTimeStatus()
{
if (task == null)
{
await Task.Delay(500);
}
await Task.Factory.StartNew
(
() =>
{
while (true)
{
Console.WriteLine(task.Status);
if (task.Status == TaskStatus.RanToCompletion)
{
break;
}
Thread.Sleep(500);
}
}
);
}
}
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static Task task;
static CancellationTokenSource timespy = new CancellationTokenSource();
static void Main()
{
Task.WaitAll(ShowTimeMain(),MonitorShowTimeStatus());
}
static async Task ShowTimeMain()
{
task = ShowTime();
try
{
await task;
}
catch // 任务取消异常
{}
}
static async Task ShowTime()
{
await Task.Factory.StartNew
(
() =>
{
int n = 10;
while (n >= 0)
{
if (timespy.IsCancellationRequested)
{
timespy.Token.ThrowIfCancellationRequested();
}
Console.WriteLine(DateTime.Now);
Thread.Sleep(1000);
n--;
}
}
, timespy.Token
);
}
static async Task MonitorShowTimeStatus()
{
if (task == null)
{
await Task.Delay(500);
}
await Task.Factory.StartNew
(
() =>
{
int n = 10;
while (true)
{
n--;
Console.WriteLine("{0,-2} {1}", n,task.Status);
if (task.Status == TaskStatus.RanToCompletion || task.Status == TaskStatus.Canceled)
{
break;
}
Thread.Sleep(500);
if (n == 0)
{
timespy.Cancel();
}
}
}
);
}
} lzy00 发表于 2022-5-23 10:47
await放while里是起什么作用呢
await 不管放在哪里都会等待 它 等待的任务执行完成后,再去执行await后面的语句。
这里是延时1秒中,在任务没有完成时,它在这个等待的时间内不会占用CPU,CPU可以去做其它的事情 学习学习 刚好用用 学习学习 刚好用用 不错,建议将task的并发执行,取消等机制也讲下,就更完整了 学习学习 学习了,Thread 在挂起状态怎么直接关闭掉? wang65424773 发表于 2021-11-17 12:51
学习了,Thread 在挂起状态怎么直接关闭掉?
线程有个abort方法! 最好可以讲讲.net最典型的的委托 个人还是比较喜欢看笔记的,毕竟俺也喜欢写笔记
页:
[1]
2