[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));
           
        }

多線程采集就完成了。其實本文講來講去主要是圍繞創建線程這一話題,技術含量相當低,就當給剛入門的朋友練練手吧!

教程每天都會更新,歡迎繼續關注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM