C军

不玩博客了!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  496 随笔 :: 0 文章 :: 634 评论 :: 571万 阅读

一、多线程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了一下。后面等待优化。

posted on   逆心  阅读(2023)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2012-11-28 CSS常用属性
点击右上角即可分享
微信分享提示