zoukankan      html  css  js  c++  java
  • [c#] 多线程网络编程应用[多线程文章采集]

        编程不能死记硬背,要靠多实践操作

        如今的网络越来越发达,分享一个文件是如此的简单。特别是有了电驴、迅雷这样的下载软件就更加如虎添翼了,想从网上下载一个几个G大小的文件,真是不费吹灰之力。好,废话太多了,直接进入咱们今天的主题吧。

       要实现像迅雷一样的多线程下载,核心问题是要将多线程的概念以及怎么实现的问题弄清。

       当然,本文技术含量很低,大牛请直接绕道。

       多线程是相对单线程来说的,具体可以参考百度百科里的解释:http://baike.baidu.com/view/65706.htm

      每个程序运行都有一个最基本的主线程,用于处理界面绘画,人机交互,后台处理等过程,因此如果是在单线程程序里操作打量耗时的动作,主界面就会很卡,甚至是无法工作。因此不管您是不是喜欢,最好都别用主线程把一切事务包揽,否则很难给用户一个舒爽的客户体验。

      那么在C#里如何实现多线程呢?

    下面让我们实现一个最简单的多线程实例;

    为了演示方便,我们新建一个winform项目,取名为 MultiThreadDemo。

    先创建一个足够让你的程序卡住不动的方法函数:

        private void Display()
            {
             while (true)
              textBox1.Text = new Random().NextDouble().ToString();
            }

    然后给button1添加调用,发现确实够卡吧,谁让你把那种死循环的事情交给主线程去做呢,一个人又画图,又要算数,哪还有时间给你答复。

    using System.Threading;

     接着补充一下button1里面的代码,给他创建一个线程,我们把这线程取名叫“UiThread”用于专门处理显示吧。

    View Code
      private void button1_Click(object sender, EventArgs e)
            {
                Thread thread = new Thread(Display);//创建一个线程
                thread.Start();
               // Display();
            }

    如果你急着运行,肯定会回过头来骂我了,怎么不行呢,是不是什么会提示:“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”。因为主线程和你创建的那个线程是两个互不相干的线程,两个陌生人怎么打交道?也就是当你这个UiThread没经过主线程同意就去调用textBox1,别人会让你那么做吗?
    因此,为了处理他俩工作不协调的问题,特意强制性取消线程警告.在构造函数里添加一句:

     public Form1()
            {
                InitializeComponent();
                Control.CheckForIllegalCrossThreadCalls = false;//加上这句就不会警告了
            }

    这样一个简单的多线程程序就诞生了。不过有个时候有很多代码需要用到委托,又不想单独创建一个函数,就可以这样做:

    View Code
    private void button1_Click(object sender, EventArgs e)
            {
    
                ThreadStart threadStart = new ThreadStart(delegate { Display(); });//创建一个委托,这样可以调用任意参数的函数了,甚至是零星的代码都可以
                Thread thread = new Thread(threadStart);
                thread.Start();
    
            }

    不过并不推荐这么做,这在线程上是不安全的,有很大的概率会使程序奔溃。
    通过上面的练习,我们知道创建一个线程可以多做一些事,同样,我们多创建几个线程,做的事岂不是更多?这是必须的。

    接下来正式走进我们今天的正题:多线程采集

    要想多线程采集,首先要解决单个下载。

    using System.Net;
    using System.IO;
    View Code
     /// <summary>
            /// 转载请加上本人博客链接
            /// </summary>
            /// <param name="richtextBox"></param>
            /// <param name="i"></param>
            static void Request(RichTextBox richtextBox,int i)
            {
    
                richtextBox.AppendText(string.Format("线程{0}开始接收\n", Thread.CurrentThread.Name));
                ServicePointManager.DefaultConnectionLimit = 1000;
                HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format("http://news.cnblogs.com/n/{0}/", (int)i));//这里的i最嗨是158100到158999,符合博客园url规则才能采集到
                StreamWriter sw = File.CreateText(string.Format(Environment.CurrentDirectory + "\\{0}.htm", i));
    
                try
                {
                    HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                    Stream stream = httpWebResponse.GetResponseStream();
                    StreamReader sr = new StreamReader(stream);
                    string html = sr.ReadToEnd();
                   richtextBox.AppendText(string.Format(Thread.CurrentThread.Name + "接收完毕"));
                    sw.Write(html);
                    sw.Close();
                }
                catch
                {
                   richtextBox.AppendText(string.Format("线程{0}不存在此地址,跳过\n", Thread.CurrentThread.Name));
                    sw.Write(string.Format("线程{0}不存在此地址,跳过\n", Thread.CurrentThread.Name));
                    return;
                }
             }

    然后在在button2里调用

    View Code
            private void button2_Click(object sender, EventArgs e)
            {
                ThreadStart threadStart = new ThreadStart(delegate { Request(richTextBox1, 158100); });//创建一个委托,这样可以调用任意参数的函数了,甚至是零星的代码都可以
                Thread thread = new Thread(threadStart);
                thread.Start();
            }

    这样以来单次采集就完成了。
    要想像火车头一样采集,自然以目前的水平是做不到的。起码也要把批量采集做出来。无外乎使用多线程。

    View Code
     /// <summary>
            /// 转载请加上本人博客链接
            /// </summary>
            /// <param name="richtextBox"></param>
            /// <param name="i"></param>
            static void Request(RichTextBox richtextBox,int i)
            {
    
                richtextBox.AppendText(string.Format("线程{0}开始接收\n", Thread.CurrentThread.Name));
                ServicePointManager.DefaultConnectionLimit = 1000;
                HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format("http://news.cnblogs.com/n/{0}/", (int)i));//这里的i最嗨是158100到158999,符合博客园url规则才能采集到
         
               
                   
                try
                {
                    HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                    Stream stream = httpWebResponse.GetResponseStream();
                    StreamReader sr = new StreamReader(stream);
                    string html = sr.ReadToEnd();
                   richtextBox.AppendText(string.Format(Thread.CurrentThread.Name + "接收完毕\n"));
                   StreamWriter sw = File.CreateText(string.Format(Environment.CurrentDirectory + "\\{0}.htm", i));
              
                    sw.Write(html);
                    sw.Close();
                }
                catch
                {
                    richtextBox.AppendText(string.Format("线程{0}不存在此地址,跳过\n", Thread.CurrentThread.Name));
                
                }
         
             }
    
            private void button2_Click(object sender, EventArgs e)
            {
                Thread.CurrentThread.Name = "主线程";
                 Thread[] threads = new Thread[51];
                 DateTime endTime = DateTime.Now;
                 DateTime startTime = DateTime.Now;
                 TimeSpan timeSpan = endTime - startTime;
                 string span = timeSpan.TotalSeconds.ToString();
                 startTime = DateTime.Now;
                 Mutex mt = new Mutex();
                 mt.WaitOne();
                 for (int i = 158300; i >158250; i--)
                {
                        threads[158300 - i] = new Thread(new ParameterizedThreadStart(delegate { Request(richTextBox1, i); }));
                        threads[158300 - i].Name = "线程" + (i).ToString(); ;
                        threads[158300 - i].Start();
                   
                }
                 mt.ReleaseMutex();
                endTime = DateTime.Now;
                timeSpan = endTime - startTime;
                span = timeSpan.TotalSeconds.ToString();
                richTextBox1.AppendText(string.Format("多线程接受的话共花费了{0}秒钟\n", span));
               
            }

    多线程采集就完成了。其实本文讲来讲去主要是围绕创建线程这一话题,技术含量相当低,就当给刚入门的朋友练练手吧!

    教程每天都会更新,欢迎继续关注。



    ///******************************************************
    ///本文作者:凌晨的搜索者
    ///博客地址:http://www.cnblogs.com/uu102
    ///本文属于原创,如果有您需要的内容想要转载,请保留此段签名注释,否则作者将保留追究法律责任的权利。
    ///******************************************************
  • 相关阅读:
    【前端基础】webpack 概述
    Temporary Post Used For Theme Detection (1f3683c2-c37f-4fb8-ba3f-6a33842053d2
    分布式场景实用技术
    Linq中的SingleOrDefault和FirstOrDefault
    笔记:SpringBoot教程快速入门-基础-SpringBoot简介&快速入门案例(一)
    使用nacos的配置中心报错Ignore the empty nacos configuration and get it based on dataId
    Shell 命令
    django orm 笔记
    memoize
    once函数
  • 原文地址:https://www.cnblogs.com/uu102/p/2697130.html
Copyright © 2011-2022 走看看