2012-03-12 5 views
2

私は、ジョブを消費するコンシューマスレッドの有限集合を持っています。ジョブを処理すると、消費ジョブにリストされたサブジョブのリストが表示されます。私はデータベースにまだ持っていないリストからサブジョブを追加する必要があります。データベースには300万人がいるので、どのデータベースがデータベースにないのかを知るのは遅いです。私は各スレッドがその呼び出しをブロックしても構いませんが、競合状態(コード参照)があるので、遅い呼び出しでそれらをすべてロックする必要があります。したがって、そのセクションを1度に1つしか呼び出しできず、プログラムがクロールします。これを修正するために何をすればスレッドはその呼び出しのために減速しませんか?私はキューを試しましたが、スレッドがコンピュータのリストよりも速くジョブのリストをプッシュしているため、データベースに追加する必要があるものを判断できるため、キューを増やして空にすることはありません。効率的なマルチスレッドセット差へのアプローチ

マイコード:

IEnumerable<string> getUniqueJobNames(IEnumerable<job> subJobs, int setID) 
{ 
    return subJobs.Select(el => el.name) 
     .Except(db.jobs.Where(el => el.set_ID==setID).Select(el => el.name)); 
} 

//...consumer thread i 
lock(lockObj) 
{ 
    var uniqueJobNames = getUniqueJobNames(consumedJob.subJobs, consumerSetID); 
    //if there was a context switch here to some thread i+1 
    // and that thread found uniqueJobs that also were found in thread i 
    // then there will be multiple copies of the same job added in the database. 
    // So I put this section in a lock to prevent that. 
    saveJobsToDatabase(uniqueJobName, consumerSetID); 
} 
//continue consumer thread i... 
+0

何todoをしようとしている、何をやっているのかをもう一度説明することができますが、現在どのように実行しているのかについての情報がなくても、実際の作業はより明確になります。 – ntziolis

+0

先に既存のジョブのリストを取得し、 「新しい」サブジョブを並行して実行し、最後に新しいジョブを保存しますか? –

+0

問題は、例外を使用してデータベースと比較しない限り、新しいものはわかりません。出てくるすべてのサブジョブのリストをコンパイルすることができましたが、最終的にそのリストとデータベースを比較したいとき、次のリストが来るまでに完了しません。それらは、後でリストをキャッシュするか、すぐに実行するかに関係なく、Exceptメソッドを実行するよりも速く構築しています。実際にすぐに実行すると、消費者はより速く実行され、問題は複雑化します。私は、いくつかのデータ構造が役立つかもしれないと推測しています、あるいはちょうど別のアルゴリズムです。 – brandon

答えて

2

よりもむしろあなたがジョブ名の一意性を確認するために戻ってデータベースにあなたがはるかに高速に存在を確認することができますメモリへのルックアップのデータ構造に関連する情報を、可能性が行きます:

Dictionary<int, HashSet<string>> jobLookup = db.jobs.GroupBy(i => i.set_ID) 
    .ToDictionary(i => i.Key, i => new HashSet<string>(i.Select(i => i.Name))); 

これは1回だけです。あなたはまた、新しいサブジョブを入力して検索し、それを追加する必要がある場合

IEnumerable<string> getUniqueJobNames(IEnumerable<job> subJobs, int setID) 
{ 
    var existingJobs = jobLookup.ContainsKey(setID) ? jobLookup[setID] : new HashSet<string>(); 

    return subJobs.Select(el => el.Name) 
     .Except(existingJobs); 
} 

:その後、あなたが一意性をチェックする必要があるたびに、あなたは、ルックアップを使用し、それは私にははっきりしていない

lock(lockObj) 
{ 
    var uniqueJobNames = getUniqueJobNames(consumedJob.subJobs, consumerSetID); 
    //if there was a context switch here to some thread i+1 
    // and that thread found uniqueJobs that also were found in thread i 
    // then there will be multiple copies of the same job added in the database. 
    // So I put this section in a lock to prevent that. 
    saveJobsToDatabase(uniqueJobName, consumerSetID); 

    if(!jobLookup.ContainsKey(newconsumerSetID)) 
    { 
     jobLookup.Add(newconsumerSetID, new HashSet<string>(uniqueJobNames)); 
    } 
    else 
    { 
     jobLookup[newconsumerSetID] = new HashSet<string>(jobLookup[newconsumerSetID].Concat(uniqueJobNames))); 
    } 
} 
+0

良い解決策。私は毎回NlogNのルックアップを取るよりもむしろこのようなメモリを使うことになります。新しいデータをデータベースと同期させるこのデータ構造のカスタムバージョンを書くつもりです – brandon

+0

私の助言は、あまりデータ構造を複雑にしすぎず、DB /メモリを別に処理し、デバッグの問題をはるかに簡単にすることです – ntziolis

関連する問題