并行编程
并行编程:从业务实现的角度可分为数据并行与任务并行,也就是要解决的问题是以数据为核心还是以要处理的事情为核心,它以System.Threading.Tasks命名空间下的Parallel类为实现核心类。
数据并行:在不同的任务之间同事处理一些数据(采用Parallel.For或Parallel.ForEach方法来实现)
任务并行:同时执行不同的功能(采用Parallel.Invoke方法来实现)
注意:运行多线程时,如果线程访问相同的数据,就很容易出现问题。为了避免出问题,必须实现同步机制
线程池:提供了一个后台线程的池。只需要知道线程池独自管理线程,根据需要增加或减少线程池中线程数。线程池中的线程用于实现一些操作,之后任然返回线程池中,线程在线程池中重用的。
并行编程模型使用CLR线程池执行多个任务,并能自动处理工作分区、线程调度和取消、状态管理以及其他低级别的细节操作;
二 . Paraller类
Paraller 类提供了非常简单的并行性,来实现并行任务(通过线程池实现的)。
在数据并行中,For和ForEach方法会自动对源集合进行分区,这样多个线程才可以并行执行。
在任务并行中,Invoke可以并行执行任务,而且并行的任务都是异步执行的。
- Paraller.For()方法循环 ,数据并行
public static void ParallerFor()
{
var result = Parallel.For(0, 10, i =>
{
Console.WriteLine("S任务序号:{0} ,线程Id:{1}", i, Thread.CurrentThread.ManagedThreadId);
Task.Delay(10).Wait();
Console.WriteLine("E任务序号:{0} ,线程Id:{1}", i, Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("Is completed:" + result.IsCompleted);
}
- Paraller.ForEach()方法循环,数据并行
public static void ParallerlForEach()
{
string[] data = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "11", "12" };
var result = Parallel.ForEach(data, s =>
{
Console.WriteLine("data:{0} ,线程Id:{1}", s, Thread.CurrentThread.ManagedThreadId);
});
}
- Parallel.Invoke()调用多个方法,实现多个任务并行运行
public static void ParallerInvoke()
{
Parallel.Invoke(One, Two);
}
public static void One()
{
Console.WriteLine("One:{0}", Thread.CurrentThread.ManagedThreadId);
}
public static void Two()
{
Console.WriteLine("Two:{0}", Thread.CurrentThread.ManagedThreadId);
}
三. Task类(创建一个新任务,并使用线程池中的一个线程)
- 基本使用方式
/// <summary>
/// 将一个任务添加到线程池里,排队执行
/// 都是创建一个新任务,并使用线程池中的一个线程。
/// </summary>
public static void TasksUsingThradPool()
{
var tf = new TaskFactory();
//创建并启动
tf.StartNew(a => {
Console.WriteLine("StartNew 线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
}, "using a task factory");
Task.Factory.StartNew(a =>
{
Console.WriteLine("Factory.StartNew 线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
}, "factory task");
var t = new Task(a =>
{
Console.WriteLine("Start 线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
}, "Start");
t.Start();
Task.Run(() => {
Console.WriteLine("Run 线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
});
}
- 并行执行多个任务时,有时候可能需要某个任务等待另一个任务完成后才能开始执行,这时需要用到任务等待与组合。
Task.WaitAll()阻塞调用任务,直到等待的所有任务完成为止
Task.WhenAll()方法返回一个任务,从而可以使用async关键字等待结果,它不会阻塞等待的任务
Task t1 = Task.Run(() =>
{
Task.Delay(3000).Wait();
Console.WriteLine($"t1 {Task.CurrentId}");
});
Task t2 = Task.Run(() =>
{
Console.WriteLine($"t2 {Task.CurrentId}");
});
//WaitAll()阻塞调用任务,直到等待的所有任务完成为止
Task.WaitAll(t1, t2);
Console.WriteLine($"执行完WaitAll。。。");
//WhenAll()方法返回一个任务,从而可以使用async关键字等待结果,它不会阻塞等待的任务
Task.WhenAll(t1, t2);
Console.WriteLine($"执行完WhenAll。。。");
执行结果: