2012-03-01 11 views
2

私は開発中のマルチスレッドC#アプリケーションを管理するためのクラスのセットを最適に設計する方法について助けが必要です。 一連のスレッドを起動するThreadContainerクラスを正常に作成しました。 スレッドは、特定のWebサイトから財務データをダウンロードします。 渡された各Webサイトについて、同じベースURLを開きますが、異なる記号で開きます。 したがって、各ウェブサイトに渡された記号の数に等しい数の結果があります。スレッドの結果を要求されたWebサイトに応じて、異なる方法で処理しているに が続いて...ここ が簡略化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. Webページのコンテンツ
  2. は、Webページ
  3. からデータを呼び出し元にデータを送信したり、保存抽出しますデータをDBに挿入するか、またはデータをキューに挿入します。
  4. キューにアイテムがまだあるかどうかを確認し、新しいURLでスレッドを再起動すると、新しいWebページが開きます。

新しいウェブサイトを追加する必要があるたびにコードを変更する必要がないように、メソッドを設計するにはどうすればよいですか? また、データを抽出するページをダウンロードした同じAsynchThreadを使用するか、DBなどに保存する必要がありますか。私はシングル責任原則の種類以下ThreadContainerクラスを持っていると思い ...

感謝のEventArgsで

+0

対象とする.NETフレームワークのバージョンは何ですか? –

+0

.Net version 4 – Forna

+0

結果をキューにエンキューしてから、マスタースレッドでデキューします。 – 0x4f3759df

答えて

0

は、このサイトを扱う特定の実装にデリゲート/アクションを渡します。

または、URLを置くクラスのサイトとデータで実行する特定の作業を処理するメソッドを分離してください。その後、スレッドのEventArgsにSiteを渡し、コールバック内のそのサイトの特定のメソッドを呼び出します。

このようにしてcaseステートメントを削除し、それが所属するコードを移動します。

0

新しいウェブサイトを追加する必要があるたびにコード を変更する必要がないように、メソッドを設計する方法を教えてください。

これは困難な問題があります。ウェブサイトに基づいて、データを受信した後に異なるアクションを実行するため、後処理はウェブサイト上のに依存します。最良のケースは、これをより柔軟にするパターンを使用することです。そのため、コードのメンテナンスは低くなります。あなたが言ったようにしかし、あなたは、あなたがこれをやりたい場合には述べられていない。

は、呼び出し元にデータを送信したり、DBにデータを保存したり、キューにデータを挿入します。

これを行うために必要なロジックは何ですか?これは何に基づいていますか?複数の責任を負うコードから推測するのは難しいです。コードのこれらの部分を抽象化する必要があります。あなたが持っている可能性が何

は次のとおりです。

はあなたの要求を処理するためにオブジェクトを作成するファクトリパターンを使用してください。あなたのケースでは、要求は単に多分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(); 
} 

工場を使用しますパターンを使用して、要求の結果を処理するオブジェクトを作成します。この場合、キュー、データベースなどに戻します。

.NETを使用しているため、タスク並列ライブラリ(TPL)の使用をお勧めします。 4.0。これにより、コードの読み込みが容易になり、多くの複雑さが取り除かれます。キャンセルや継続などの素晴らしいこともできます。hereを始めることができます。

+0

工場のパターンをありがとう、それは面白そうです。実際には、Webサイト変数はすべてのスレッドを起動するクラスであるThreadContainerクラスに渡されます。したがって、Webサイトは、スレッドが生成される前に知られています。これは私がThreadContainerを起動する方法の例です:ThreadContainer tc = new ThreadContainer( "Earnings"、SymQueue); – Forna

+0

@Forna:私はあなたがウェブサイトを知っていることを知っています。あなたのケースでは、 'ISymbolRequest'の各タイプのデータをどのように解釈するのかを知っている' Processor'クラスを持つことが最善の方法かもしれません。 –

関連する問題