1. csharp多线程
1.1. csharp5新特性async/await
1.1.1. 性质
- async用于修饰方法,表示这是一个异步方法
- 具体实现异步是在普通的同步方式调用方法之前加上await关键字
- 使用
await
调用异步方法时,调用它的方法必须加上async关键字,即await
只能出现在使用async修饰的方法中
1.1.2. 概念
1.1.2.1. 异步方法
概念:异步方法在完成其工作之前立即返回到调用方法,调用方法可以继续执行后面的操作,如果异步方法有返回结果,调用方法在获取结果时如果异步方法没有完成,调用方法会执行阻塞等待操作。 异步方法的性质:
- 方法签名包含
async
修饰 - 返回值为以下三种类型:
- void:不需要返回值
Task
:不需要返回值,但可能需要获取方法的状态Task<T>
:需要一个T类型的返回值
- 方法参数不能为out、ref参数
- 方法名约定俗成以”Async”为后缀,如
CalculateAsync
代表一个异步计算的方法
1.1.3. Example
[assembly: log4net.Config.XmlConfigurator(ConfigFile ="log4net.config",Watch =true)]
namespace _2023_4_1_DownloadDemo
{
class Program2
{
private static ILog log=LogManager.GetLogger("Program2");
public Program2()
{
}
static void Main(string[] args)
{
Task<int> task = CalculateAsync(5, 6);
//处理其他事情...
Print();
log.Info(task.Result);
Console.ReadKey();
}
private static async Task<int> CalculateAsync(int a, int b)
{
Func<int> func = () =>
{
log.Info($"Thread:{ Thread.CurrentThread.GetHashCode()}");
//这里是一些耗时的操作
Thread.Sleep(3000);
return GetSum(a, b);
};
int sum = await Task.Run(
func
);
return sum;
}
private static int GetSum(int a, int b) { return a + b; }
private static void Print()
{
Task.Run(() => {
log.Info($"Thread:{Thread.CurrentThread.GetHashCode()}");
log.Info("asasd");
});
}
}
}
输出:
2023-04-01 11:27:59,949 [4] INFO - Thread:4
2023-04-01 11:27:59,949 [5] INFO - Thread:5
2023-04-01 11:27:59,957 [5] INFO - asasd
2023-04-01 11:28:02,970 [1] INFO - 11
1.1.4. Task.Run()方法
Task.Run()
是一个用来执行自定义异步任务的静态方法,参数是Action
、Func
这些委托类型。
1.1.5. 取消异步任务
System.Threading.Tasks中有两个类为此目的设计:CancellationToken
和CancellationTokenSource
- CancellationToken对象包含一个任务是否应被取消的信息
- 拥有CancellationToken对象的任务定期检查token状态,如果属性
IsCancellationRequested
为true,任务停止操作并返回 - CancellationToken不可逆,一旦属性
IsCancellationRequested
设置成true,就不能更改 CancellationTokenSource
对象创建可以分配给不同任务的CancellationToken对象,任何持有CancellationTokenSource的对象都可以调用其Cancel()
方法,这会将CancellationToken对象的属性IsCancellationRequested
为true
Example
public class Program4
{
private static ILog log = LogManager.GetLogger("Program4");
public static void Run()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
MyClass mc = new MyClass();
Task t=mc.RunAsync(token);
Thread.Sleep(3000);
tokenSource.Cancel();
t.Wait();
log.Info($"was cancelled:{token.IsCancellationRequested}");
Console.Read();
}
class MyClass
{
internal async Task RunAsync(CancellationToken token)
{
if (token.IsCancellationRequested)
{ return; }
await Task.Run(() => CycleMethod(token), token);
}
private void CycleMethod(CancellationToken token)
{
log.Info("Starting cycle");
const int max = 5;
for (int i = 1; i <= max; i++)
{
if (token.IsCancellationRequested)
{
return;
}
Thread.Sleep(1000);
log.Info($"{i} of {max} iterations completed.");
}
}
}
}
输出:
2023-04-01 15:18:14,734 [4] INFO - Starting cycle
2023-04-01 15:18:15,750 [4] INFO - 1 of 5 iterations completed.
2023-04-01 15:18:16,753 [4] INFO - 2 of 5 iterations completed.
2023-04-01 15:18:17,759 [4] INFO - 3 of 5 iterations completed.
2023-04-01 15:18:17,760 [1] INFO - was cancelled:True
BackgroundWorker
async/await适合处理在后台完成的不相关的小任务,如果后台任务需要持续执行并且要和主线程通信,这个时候的异步适合使用BackgroundWorker
类