一、多线程I/O
1、单线程采集100个页面
class Program { static int i = 6991275; static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); getTitle(); sw.Stop(); Console.WriteLine("采集100个页面完成,用时:" + sw.ElapsedMilliseconds + "毫秒"); Console.ReadKey(); } static void getTitle() { for (int j = 0; j < 100; j++) { WebClient wc = new WebClient(); wc.BaseAddress = "http://www.juedui100.com/"; wc.Encoding = Encoding.UTF8; string html = wc.DownloadString("user/" + ++i + ".html"); Regex reg = new Regex(@"<title>(.*)</title>"); Console.WriteLine(reg.Match(html)); } } }
输出:
2、多线程采集100个页面
class Program { static int i = 6991275; static volatile int k = 1; static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 5; i++) { ThreadPool.QueueUserWorkItem(getTitle); } while (true) { if (k == 5) { sw.Stop(); break; } } Console.WriteLine("采集100个页面完成,用时:" + sw.ElapsedMilliseconds + "毫秒"); Console.ReadKey(); } static void getTitle(object o) { while(i < 6991375) { WebClient wc = new WebClient(); wc.BaseAddress = "http://www.juedui100.com/"; wc.Encoding = Encoding.UTF8; string html = wc.DownloadString("user/" + Interlocked.Increment(ref i) + ".html"); Regex reg = new Regex(@"<title>(.*)</title>"); Console.WriteLine(reg.Match(html)); } k++; } }
输出如下:
单纯从执行时间来看,采集100个页面,用5个线程效率提升2倍多,当然这跟带宽也有关系啦。
有问题,好像K++多个线程执行的时候有问题,也要Interlocked.Increment。
二、多线程计算
今天接手了三维计算,当集合里的数量超过100个时,计算就明显变慢,三维计算是一位已离职的同事写的,尽可能的调优之后,由于算法看得还不是特别懂,只是感觉效率比较低。觉得不行,还要多线程。150个元素的集合,单线程要13秒,而启用多线程之后,可以将时间优化到5秒,速度可以提升60%。
归根结底,这种操作慢的问题,还是算法效率不高,一时间也理解不了。要想进一步提升,后面再看懂了它的算法之后,还是把算法的效率解决才是王道,暂时先用多线程扛一扛。
#region 多线程 int aRound = 25; rCount = (int)Math.Ceiling((double)hardwares.Count / aRound); List<List<IngoHardwareObject>> listAll = new List<List<IngoHardwareObject>>(); for (int i = 0; i < rCount; i++) { List<IngoHardwareObject> listA = hardwares.Skip(i * aRound).Take(aRound).ToList(); listAll.Add(listA); } foreach (List<IngoHardwareObject> listA in listAll) { HP hp1 = new HP(); hp1.hardwares = listA; hp1.planks = planks; ThreadPool.QueueUserWorkItem(CalCollision, hp1); } while (true) { if (aCount == rCount) { break; } } #endregion
测试时,由于集合的计算是互不相干的,唯一相关的就是汇总结果要统计到同一个哈希表,所以可以启用多线程。但写入就不能多个线程同时写入了,要Lock一下,否则数据会乱七八糟,我也猜不出会有什么后果。
简单说来,其里面的逻辑就是,集合有150个元素,把这个List分成多个,每个25个元素,多个线程同时开始计算。
如果不用多线程,就是算完一个,又算一个。每个集合25个元素,那就是6个线程,一有机会就算。
为什么分成一个组25个?这个是调试出来的,我发现25个是最快的,所以设置成了25个。如果不是因为这个计算太慢,这样搞多线程,其实是得不偿失的,为啥?因为你又要切割集合,又要装载线程,又要分批汇总。只有这种单线程明显慢的计算,才能从多线程中获益!
static void CalCollision(object OHP) { Dictionary<IngoHardwareObject, Collision> dicC = new Dictionary<IngoHardwareObject, Collision>(); HP hp = OHP as HP; foreach (IngoHardwareObject ingoHard in hp.hardwares) { List<IngoPlankObject> listNearPlank = hp.planks.FindAll(o => o.MayCollision(ingoHard) && o.Key != ingoHard.Key).ToList(); if (listNearPlank.Any()) { Collision collision = new Collision() { collisionType = CollisionType.HardwareVsPlank }; if (ingoHard.HardwareType == HardwareType.双头连杆) { List<CollisionInfo> collisionInfo = CheckCollisionMul(ingoHard, listNearPlank); if (collisionInfo.Any()) { collision.Infos.AddRange(collisionInfo); } } else { for (int i = 0; i < listNearPlank.Count; i++) { List<CollisionInfo> collisionInfo = CheckHardwareCollisionMul(ingoHard, listNearPlank[i]); if (collisionInfo.Any()) { collision.Infos.AddRange(collisionInfo); } } } dicC[ingoHard] = collision; } } lock(objDic) { foreach(KeyValuePair<IngoHardwareObject, Collision> item in dicC) { dicCollision[item.Key] = item.Value; } } aCount++; }
由于不允许多个线程同时写入Dic,所以Lock了一下。后面等待优化。