C#實現多線程

來源:互聯網
上載者:User

標籤:

多線程在C#中並不難實現。它有一個命名空間:System.Threading,提供了多線程的支援。

要開啟一個新線程,需要以下的初始化:

ThreadStart startDownload = new ThreadStart( DownLoad ); //線程起始設定:即每個線程都執行DownLoad(),注意:DownLoad()必須為不帶有參數的方法

Thread downloadThread = new Thread( startDownload ); //執行個體化要開啟的新類

downloadThread.Start();//開啟線程

 

由於線程起始時啟動的方法不能帶有參數,這就為多線程共用資源添加了麻煩。不過我們可以用類級變數(當然也可以使用其它方法,筆者認為此方法最簡單易用)來解決這個問題。知道開啟多線程下載的方法後,大家可能會產生幾個疑問:

1.       如何控制線程的數量?

2.       如何防止多線程下載同一網頁?

3.       如何判斷線程結束?

4.       如何控制線程結束?

 

下面就這幾個問題提出解決方案:

1.       線程數量我們可以通過for迴圈來實現,就如同當年初學編程的打點程式一樣。

比如已知使用者指定了n(它是一個int型變數)個線程吧,可以用如下方法開啟五個線程

Thread[] downloadThread;//聲名下載線程,這是C#的優勢,即數組初始化時,不需要指定其長度,可以在使用時才指定。這個聲名應為類級,這樣也就為其它方法控制項它們提供了可能

ThreadStart startDownload = new ThreadStart( DownLoad );//線程起始設定:即每個線程都執行DownLoad()

downloadThread = new Thread[ n ];//為線程申請資源,確定線程總數

for( int i = 0; i < n; i++ )//開啟指定數量的線程數

{

    downloadThread[i] = new Thread( startDownload );//指定線程起始設定

    downloadThread[i].Start();//逐個開啟線程

}

好了,實現控制開啟線程數是不是很簡單啊?

2.       下面出現的一個問題:所有的線程都調用DonwLoad()方法,這樣如何避免它們同時下載同一個網頁呢?

這個問題也好解決,只要建立一下Url地址表,表中的每個地址只允許被一個線程申請即可。具體實現:

可以利用資料庫,建立一個表,表中有四列,其中一列專門用於儲存Url地址,另外兩列分別存放地址對應的線程以及該地址被申請的次數,最後一列存放下載的內容。(當然,對應線程一列不是必要的)。當有線程申請後,將對應線程一列設定為當前線程編號,並將是否申請過一列設定為申請一次,這樣,別的線程就無法申請該頁。如果下載成功,則將內容存入內容列。如果不成功,內容列仍為空白,作為是否再次下載的依據之一,如果反覆不成功,則進程將於達到重試次數(對應該地址被申請的次數,使用者可設)後,申請下一個Url地址。主要的代碼如下(以VFP為例):

<建立表>

CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I ) &&建立一個表ctablename.dbf,含有地址、常值內容、已經嘗試下載次數、線程標誌(初值為-1,線程標誌是從0開始的整數)四個欄位

<提取Url地址>

cfullname = (ctablename) + ‘.dbf‘&&為表添加副檔名

USE (cfullname)

GO TOP

LOCATE FOR (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND ( threadNum = thisNum OR threadNum = - 1) ) &&尋找尚未下載成功且應下載的屬於本線程許可權的Url地址,thisNum是當前線程的編號,可以通過參數傳遞得到

gotUrl = curl

recNum = RECNO()

IF recNum <= RECCOUNT() THEN &&如果在列表中找到這樣的Url地址

UPDATE (cfullname) SET ldowned = ( ldowned + 1 ) , threadNum = thisNum WHERE RECNO() = recNum &&更新表,將此記錄更新為已申請,即下載次數加1,線程標誌列設為本線程的編號。

<下載內容>

cfulltablename = (ctablename) + ‘.dbf‘

USE (cfulltablename)

SET EXACT ON

LOCATE FOR curl = (csiteurl) && csiteurl是參數,為下載到的內容所對應的Url地址

recNumNow = RECNO()&&得到含有此地址的記錄號

UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() = recNumNow &&插入對應地址的對應內容

<插入新地址>

ctablename = (ctablename) + ‘.dbf‘

USE (ctablename)

GO TOP

SET EXACT ON

LOCATE FOR curl = (cnewurl) &&尋找有無此地址

IF RECNO() > RECCOUNT() THEN &&如果尚無此地址

SET CARRY OFF

INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum ) VALUES ( (cnewurl) , "" , 0 , -1 ) &&將首頁地址添加到列表

好了,這樣就解決了多線程中,線程衝突。當然,去重問題也可以在C#語言內解決,只根建立一個臨時檔案(文本就可以),儲存所有的Url地址,差對它們設定相應的屬性即可,但尋找效率可能不及資料庫快。

3.       線程結束是很難判斷的,因為它總是在尋找新的連結。用者認為可以假設:線程重複N次以後還是沒有能申請到新的Url地址,那麼可以認為它已經下載完了所有連結。主要代碼如下:

string url = "";

int times = 0;

while ( url == "" )//如果沒有找到合格記錄,則不斷地尋找合格記錄

{

    url = getUrl.GetAUrl( …… );//調用GetAUrl方法,試圖得到一個url值

    if ( url == "" )//如果沒有找到

    {

       times ++;//嘗試次數自增

       continue; //進行下一次嘗試

    }

    if ( times > N ) //如果已經嘗試夠了次數,則退出進程

    {

       downloadThread[i].Abort; //退出進程

    }

    else//如果沒有嘗試夠次數

    {

       Times = 0; //嘗試次數歸零處理

    }

    //進行下一步針對得到的Url的處理

}

4.       這個問題相對簡單,因為在問題一中已經建議,將線程聲名為類級數組,這樣就很易於控制。只要用一個for迴圈即可結束。代碼如下:

for( int i = 0; i < n; i++ )//關閉指定數量n的線程數

{

    downloadThread[i].Abort();//逐個關閉線程

}

 

附帶一個朋友的友情連結

http://www.tjjxnjy.com

http://www.cdnjy.com

http://www.beijingnjy.com

http://www.cqnjy.com

http://www.cztnjl.com

 

 

C#實現多線程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.