中国大学慕课-C#程序设计-第11讲-多线程与异步编程 之 并行编程
1. 并行编程
并行编程(C#4, 5以上),简单来时,就是多个CPU可以同时执行多个任务;
- Task.Run需要一个委托,常用的是lamda表达式,Task.Run执行某个任务并返回结果;
- Task.Run后面的语句会继续并行执行;
- double result = task.Result; 等待直到获得结果;
- Task.WaitAll(task数组),等待Task.Run的任务都执行完了,再接着往下走;
- task.ContinueWith(另一个task),让 task任务一个接一个的执行;
Demo
using System;
using System.Threading;
using System.Threading.Tasks;
class Demo
{
private static int i;
static void Main(string []args)
{
Task<double>[] tasks = { Task.Run( () => SomeFun()), Task.Run( () => SomeFun()) };
for ( i = 0; i < tasks.Length; i++ )
{
Console.WriteLine(tasks[i].Status);
Console.WriteLine(tasks[i].Result);
}
Task.WaitAll(tasks);
}
public static double SomeFun()
{
Thread.Sleep(5000);
return 0;
}
}
Demo Parallel.Invoke
using System;
using System.Threading;
using System.Threading.Tasks;
class TestParallelInvoke
{
static void Main(string[] args)
{
Action[] actions = { new Action(DoSometing), DoSometing };
Parallel.Invoke( actions );
// actions执行完后才会去执行下面
Console.WriteLine("主函数所在线程"+Thread.CurrentThread.ManagedThreadId);
Console.ReadKey();
}
static void DoSometing()
{
Console.WriteLine("函数所在线程"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(2000);
}
}
Demo Parallel.For
using System;
using System.Threading;
using System.Threading.Tasks;
class T
{
static void Main(string[] args)
{
Parallel.For(0, 10, i =>
{
Console.WriteLine("i={0}, fac={1}, 线程id={2}",
i, Calc(i),
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
});
Console.ReadLine();
}
static double Calc(int n)
{
double f = 1;
for(int i=1; i<=n; i++ ) f*=i;
Thread.Sleep(1000);
return f;
}
}
Demo Parallel.ForEach
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
class T
{
static void Main(string []args)
{
List<double> dList = new List<double>();
for (int i = 0; i <= 4 ; i++)
{
dList.Add(i * i);
}
ParallelLoopResult loop_result = Parallel.ForEach(dList, (double x, ParallelLoopState loop_state) =>
{
if (x == 400)
{
loop_state.Break();
}
Console.WriteLine("x = {0}, thread id = {1} \n", x, Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("IsCompleted: {0}",
loop_result.IsCompleted);
Console.WriteLine("BreakValue: {0}",
loop_result.LowestBreakIteration.HasValue);
Console.ReadLine();
}
}
Demo 并行计算矩阵
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DemoParallelComputeMatric
{
class Program
{
static void Main(string[] args)
{
int m = 480;
int n = 640;
int t = 640;
double[,] mat_A = new double[m, n];
double[,] mat_B = new double[n, t];
double[,] mat_R_1 = new double[m, t];
double[,] mat_R_2 = new double[m, t];
InitMatrix(mat_A);
InitMatrix(mat_B);
InitMatrix(mat_R_1);
InitMatrix(mat_R_2);
Console.WriteLine("矩阵乘法");
Stopwatch sw = new Stopwatch();
sw.Start();
MultiMatrixNormal(mat_A, mat_B, mat_R_1);
sw.Stop();
Console.WriteLine("普通方法所用时间:" + sw.ElapsedMilliseconds);
sw.Restart();
MultiMatrixParallel(mat_A, mat_B, mat_R_2);
sw.Stop();
Console.WriteLine("并行方法所用时间:" + sw.ElapsedMilliseconds);
Console.ReadLine();
}
static void InitMatrix(double[,] mat)
{
int m = mat.GetLength(0);
int n = mat.GetLength(1);
Random rnd = new Random();
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
mat[i, j] = rnd.Next();
}
}
}
static void MultiMatrixNormal(double[,] mat_A, double[,] mat_B, double[,] mat_R)
{
int m = mat_A.GetLength(0);
int n = mat_A.GetLength(1);
int t = mat_R.GetLength(1);
for (int i = 0; i < m; i++)
{
for (int j = 0; j < t; j++)
{
double temp = 0;
for (int k = 0; k < n; k++)
{
temp = mat_A[i, k] * mat_B[k, j];
}
mat_R[i, j] = temp;
}
}
}
static void MultiMatrixParallel(double[,] mat_A, double[,] mat_B, double[,] mat_R)
{
int m = mat_A.GetLength(0);
int n = mat_A.GetLength(1);
int t = mat_R.GetLength(1);
Parallel.For(0, m, i =>
{
for (int j = 0; j < t; j++)
{
double temp = 0;
for (int k = 0; k < n; k++)
{
temp = mat_A[i, k] * mat_B[k, j];
}
mat_R[i, j] = temp;
}
});
}
}
}
运行结果:
Demo
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Demo_Linq
{
class Program
{
const int count = 10000000;
static void Main(string[] args)
{
var dic = LoadData();
Stopwatch watch = new Stopwatch();
//串行读取
watch.Start();
var query_1 = (from n in dic.Values where n.Age > 20 && n.Age < 25 select n).ToList();
watch.Stop();
Console.WriteLine("串行计算耗费时间{0}", watch.ElapsedMilliseconds);
//并行读取
watch.Restart();
var query_2 = (from n in dic.Values.AsParallel() where n.Age > 20 && n.Age < 25 select n).ToList();
watch.Stop();
Console.WriteLine("并行计算耗费时间{0}", watch.ElapsedMilliseconds);
Console.ReadLine();
}
//ConcurrentDictionary 表示可由多个线程同事访问的键/值对的线程安全集合
public static ConcurrentDictionary<int, Student> LoadData()
{
ConcurrentDictionary<int, Student> stu_dic = new ConcurrentDictionary<int, Student>();
Parallel.For(0, count, (i) =>
{
Student single_stu = new Student()
{
ID = i,
Name = "n" + i,
Age = i % 151,
CreateTime = DateTime.Now.AddMilliseconds(i)
};
stu_dic.TryAdd(i, single_stu);
});
return stu_dic;
}
}
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public DateTime CreateTime { get; set; }
}
}
count小的时候还是建议使用串行模式,效率比并行要快。