2012-03-01 57 views
2

我需要關於如何最好地設計一組類用於管理多線程C#應用程序,我發展一些幫助。 我已經成功創建了一個ThreadContainer類來啓動一系列線程。 主題從特定網站下載財務數據。 對於每個通過的網站,他們將打開相同的基本網址,但使用不同的符號。 因此,#結果等於每個網站傳遞的符號數量。 然後,根據該請求的線程結果以不同的方式處理的網站上... 這裏是簡化ThreadContainer代碼:一流的設計 - 如何管理多個線程響應

public class ThreadContainer 
{ 
private int ConcurrentThreads; 
private string Website; 
public string URL; 
private Queue SymQueue; 

//Constructor 
public ThreadContainer(string website, Queue symQueue) 
{ 
    Website = website; 
    SymQueue = symQueue; 
} 

//Start 
public void start(int concurrent) 
{ 
    ConcurrentThreads = concurrent; 

    //Start the Concurrent Threads 
    for (int ThreadNum = 1; ThreadNum <= ConcurrentThreads; ThreadNum++) 
    { 
     //Get a symbol from the queue 
     Sym = SymQueue.Dequeue().ToString(); 

     //Build the URL 
     URL = string.Format(Constants.URL(Website), Sym); 

     //Create a new Asynch thread 
     AsynchThread j = new AsynchThread(ThreadNum); 

     //Start the AsyncThread class with the BackgoundWorker 
     j.Start(Sym, URL); 
    } 
} 

//Method called when the Backgroundworker thread has terminated 
private void AsynchThread1_JobCompleted(object sender, EventArgs e) 
{ 
    // Get the AsynchThread object 
    AsynchThread j = (AsynchThread)sender; 

     //Get the symbol name 
     String Sym = j.Sym; 

     //Get the result with the Webpage content 
     RunWorkerCompletedEventArgs re = e as RunWorkerCompletedEventArgs; 
     String result = re.Result.ToString(); 

     /* HERE EACH THREAD RETURNS THE WEBSITE CONTENT. 
     * DEPENDING ON THE WEBSITE THAT WAS REQUESTED SEVERAL ACTIONS MAY BE EXECUTED. 
     */ 
     switch(website) 
     { 
      case "WebsiteA": 
       // With WebsiteA I would like to : 
       // 1. extract the symbol data 
       // 2. return the result for this symbol to the calling class. 

      case "WebsiteB": 
       // With WebsiteB I would like to: 
       // 1. extract the symbol data (Webpage design is different from WebsiteA) 
       // 2. store each symbol data in a database table 

      case "WebsiteC": 
       // With WebsiteB I would like to: 
       // 1. extract the symbol data (Webpage design is different from WebsiteA and WebsiteB) 
       // 2. put the results in a queue 

      case ... 

      default:    
       return ""; 
     }   

     // Reuse the thread that has just completed 
     //If there are items left in the queue... 
     if (SymQueue.Count > 0) 
      //...get the new Sym value... 
      NewSym = SymQueue.Dequeue().ToString(); 

     //If NewSym is valid ... 
     if (!String.IsNullOrEmpty(NewSym)) 
     { 
      //...build the URL... 
      String NewURL = string.Format(Constants.URL(Website), NewSym); 

      //...then restart the thread with the new parameters 
      j.Start(NewSym, NewURL); 
     }  
    } 
} 

我想知道什麼是設計的最好方式AsynchThread1_JobCompleted 方法。 當每個線程終止,應執行以下任務,這種方法被稱爲:

  1. 得到的網頁內容
  2. 從網頁中提取數據
  3. 將數據發送給調用者或保存數據到數據庫或將數據插入到隊列中。
  4. 檢查隊列是否仍有項目,並使用新的URL重新啓動線程,以便打開新的網頁。

我該如何設計方法,以便每次需要添加新網站時都不必修改代碼? 另外,我應該使用相同的AsynchThread,下載頁面提取數據,保存到數據庫等...或者更好的另一個線程呢? 我想有以下一種單一職責原則的ThreadContainer類...

感謝

+0

您定位的是什麼版本的.NET框架? – 2012-03-01 16:04:29

+0

.Net版本4. – Forna 2012-03-01 16:06:09

+0

也許只是將結果排入隊列,然後使用主線程將其出隊。 – 0x4f3759df 2012-03-01 16:40:45

回答

0

在EventArgs的通過委託/行動,它處理這個網站具體實施。

或者更好地隔離的一類網站,在這裏你把網址,並且要與數據進行的方法來處理的具體工作。然後在EventArgs中爲該線程傳遞Site,並在回調中調用該Site的具體方法。

這樣,你要刪除case聲明,並移動它所屬的代碼。

0

我該如何設計該方法,以便每次需要添加新網站時都不必修改代碼 ?

沒有您的設計,使這個困難的問題。根據網站,您希望在收到數據後執行不同的操作,因此您的後期處理取決於網站上的。你最好的情況是使用一個更靈活的模式,所以你的代碼維護很少。但是您還沒有說明在什麼情況下您想要這樣做,如您所說:

將數據發送回調用程序或將數據保存到數據庫或將數據插入到隊列中。

這是什麼邏輯要做到這一點需要?這是基於什麼?很難從您的代碼推導出具有多重責任的代碼。您需要將代碼的這些部分抽象出來。

什麼,你可以有是:

使用工廠模式來創建一個對象來處理您的請求。你的情況的請求是簡單地用URL的對象和符號的隊列來處理,也許是這樣的:

interface ISymbolRequest 
{ 
    string Url; 
    Queue<string> Symbols; 
} 

和處理器也許是這樣的:

abstract class SymbolProcessor 
{ 
    protected ISymbolRequest _Request; 
    public SymbolProcessor(ISymbolRequest request) 
    { 
     _Request = request; 
    } 
    public abstract void GetSymbolData(); 
    public abstract void PostProcessSymbolData(); 
} 

使用工廠模式創建一個對象,處理該請求的結果,在你的情況下,它會把它放回隊列,數據庫等。

我也建議使用任務並行庫(TPL),因爲你使用.NET 4.0。這使得你的代碼更容易閱讀,並且包含了很多複雜性。你也可以做很多好事,比如取消,延續等。你可以開始here

+0

感謝工廠模式,它看起來很有趣。實際上,網站變量被傳遞給ThreadContainer類,該類是啓動所有線程的類。所以網站在任何線程生成之前都是已知的。這是我如何啓動ThreadContainer的一個例子:ThreadContainer tc = new ThreadContainer(「Earnings」,SymQueue); – Forna 2012-03-01 18:24:21

+0

@Forna:我知道你知道這個網站。在你的情況下,最好有一個處理器類來知道如何解釋每種類型的ISymbolRequest的數據 - 這正是我所掌握的。 – 2012-03-01 19:17:29