C#并发
并发
并发可以通过多线程(线程池)、异步编程、响应式编程实现
多线程包括并行(把正在执行的大量的任务分割成小块,分配给多个同时运行的线程)
异步编程
使用两个关键字: async和await async加在方法声明上, 作用是使方法内的await关键字生效, 如果async方法有返回值, 应该返回Task
有些细节需要注意: 1.一定要避免使用Task.Wait 或 Task
2.一个async方法第一个同步程序块在调用这个方法的线程中运行, 但其他同步块运行线程需要根据情况决定
每个方法会试图在原始的上下文中恢复运行, 如果在UI线程中调用, 则在此UI线程中执行, 如果在线程池中调用, 则在线程池线程上运行
要避免这种错误行为, 可以在await中调用ConfigAwait方法, 将continueOnCapturedContext设置为false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static async void DoSomething()
{
Console.WriteLine(10);
await DoTask(); //加await则异步等待, 不加则直接往下运行
Console.WriteLine(20);
}
static async Task DoTask()
{
int timer = 10;
while(timer-->=0)
{
Console.WriteLine("Task:" + timer);
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
并行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
internal partial class Program
{
//相比 PLINQ,Parallel 类与系统中其他进程配合得更好。而PLINQ 的代码更加简洁
//由于需要读写共享数据, 使用阻塞锁, 但lock与async不兼容,如果代码块中有使用await则需要使用异步锁
//数据并行1, 使用Parallel.ForEach
static int DataParallel_1(List<int> listNumber)
{
int sum = 0;
object readlock = new object();
//
Parallel.ForEach(listNumber, val => { lock (readlock) { sum += val; } });
return sum;
}
//数据并行2, 使用PLINQ
static int DataParallel_2(List<int> listNumber)
{
int sum = 0;
object readlock = new object();
listNumber.AsParallel().ForAll(val => { lock (readlock) { sum += val; } });
return sum;
}
//任务并行
static int TaskParallel(List<int> listNumber)
{
int result1 = 0, result2 = 0;
Parallel.Invoke(
() => GetSum(listNumber, 0, listNumber.Count / 2, out result1),
() => GetSum(listNumber, listNumber.Count / 2, listNumber.Count, out result2)
);
return result1 + result2;
}
static void GetSum(List<int> arr, int left, int right, out int result)
{
int _result = 0;
for (int i = left; i < right; i++)
{
_result += arr[i];
}
result = _result;
}
public static void Main4()
{
int size = 10000;
List<int> listNumber = new List<int>(size);
for (int i = 0; i < size; ++i)
{
listNumber.Add(i);
}
int result = DataParallel_1(listNumber);
Console.WriteLine($"DataParallel_1 sum = {result}");
result = DataParallel_2(listNumber);
Console.WriteLine($"DataParallel_2 sum = {result}");
result = TaskParallel(listNumber);
Console.WriteLine($"TaskParallel sum = {result}");
Console.ReadLine();
}
}
本文由作者按照 CC BY 4.0 进行授权