0

コードにマルチスレッド部分を追加しました。

 public class ThreadClassSeqGroups
    {
        public Dictionary<string, string> seqGroup;
        public Dictionary<string, List<SearchAlgorithm.CandidateStr>> completeModels;
        public Dictionary<string, List<SearchAlgorithm.CandidateStr>> partialModels;
        private Thread nativeThread;

        public ThreadClassSeqGroups(Dictionary<string, string> seqs)
        {
            seqGroup = seqs;
            completeModels  = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
            partialModels   = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
        }

        public void Run(DescrStrDetail dsd, DescrStrDetail.SortUnit primarySeedSu,
            List<ushort> secondarySeedOrder, double partialCutoff)
        {
            nativeThread = new Thread(() => this._run(dsd, primarySeedSu, secondarySeedOrder, partialCutoff));
            nativeThread.Priority = ThreadPriority.Highest;
            nativeThread.Start();
        }

        public void _run(DescrStrDetail dsd, DescrStrDetail.SortUnit primarySeedSu,
            List<ushort> secondarySeedOrder, double partialCutoff)
        {
            int groupSize = this.seqGroup.Count;
            int seqCount = 0;
            foreach (KeyValuePair<string, string> p in seqGroup)
            {
                Console.WriteLine("ThreadID {0} (priority:{1}):\t#{2}/{3} SeqName: {4}",
                    nativeThread.ManagedThreadId, nativeThread.Priority.ToString(), ++seqCount, groupSize, p.Key);
                List<SearchAlgorithm.CandidateStr> tmpCompleteModels, tmpPartialModels;
                SearchAlgorithm.SearchInBothDirections(
                        p.Value.ToUpper().Replace('T', 'U'), dsd, primarySeedSu, secondarySeedOrder, partialCutoff,
                        out tmpCompleteModels, out tmpPartialModels);
                completeModels.Add(p.Key, tmpCompleteModels);
                partialModels.Add(p.Key, tmpPartialModels);
            }
        }

        public void Join()
        {
            nativeThread.Join();
        }

    }

class Program
{
    public static int _paramSeqGroupSize = 2000;
    static void Main(Dictionary<string, string> rawSeqs)
    {
        // Split the whole rawSeqs (Dict<name, seq>) into several groups
        Dictionary<string, string>[] rawSeqGroups = SplitSeqFasta(rawSeqs, _paramSeqGroupSize);


        // Create a thread for each seqGroup and run
        var threadSeqGroups = new MultiThreading.ThreadClassSeqGroups[rawSeqGroups.Length];
        for (int i = 0; i < rawSeqGroups.Length; i++)
        {
            threadSeqGroups[i] = new MultiThreading.ThreadClassSeqGroups(rawSeqGroups[i]);
            //threadSeqGroups[i].SetPriority();
            threadSeqGroups[i].Run(dsd, primarySeedSu, secondarySeedOrder, _paramPartialCutoff);
        }

        // Merge results from threads after the thread finish
        var allCompleteModels   = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
        var allPartialModels    = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
        foreach (MultiThreading.ThreadClassSeqGroups t in threadSeqGroups)
        {
            t.Join();
            foreach (string name in t.completeModels.Keys)
            {
                allCompleteModels.Add(name, t.completeModels[name]);
            }
            foreach (string name in t.partialModels.Keys)
            {
                allPartialModels.Add(name, t.partialModels[name]);
            }
        }
    }
}

ただし、複数のスレッドを使用する場合の速度は単一のスレッドよりもはるかに遅く、CPU負荷は通常<10%です。

例えば:

入力ファイルには2500個の文字列が含まれています

_paramGroupSize = 3000、メインスレッド+1計算スレッドのコスト200秒

_paramGroupSize = 400、メインスレッド+ 7つの計算スレッドのコストははるかに高くなります(10分以上実行した後に強制終了しました)。

私の実装に問題はありますか?それをスピードアップする方法は?

ありがとう。

4

3 に答える 3

3

複数のスレッドと並行してファイルを処理しようとしているように思われます。メカニカルディスクが1つしかない場合、これは悪い考えです。

基本的に、ディスクのヘッドは、読み取り要求ごとに次の読み取り場所を探す必要があります。これはコストのかかる操作であり、複数のスレッドが読み取りコマンドを発行するため、各スレッドが順番に実行されるときにヘッドがバウンドすることを意味します。これにより、単一のスレッドが読み取りを行う場合と比較して、パフォーマンスが大幅に低下します。

于 2012-07-27T18:30:05.857 に答える
0

マルチスレッド化前のコードは何でしたか?このコードが何をしているのかを判断するのは難しく、「機能している」コードの多くは検索アルゴリズムに隠されているようです。ただし、いくつかの考え:

  1. 「入力ファイル」について言及しましたが、これはコードに明確に示されていません。ファイルアクセスがスレッド化されている場合、ファイルアクセスがボトルネックになるため、パフォーマンスは向上しません。
  2. CPUコアよりも多くのスレッドを作成すると、最終的にパフォーマンスが低下します(各スレッドが異なるリソースで待機するようにブロックされていない場合)。あなたの場合、合計8つのスレッドが多すぎることをお勧めします。
  3. メソッド内のDescrStrDetail変数からすべての子スレッドに渡されるクラスを介して、多くのデータ(メモリ)アクセスが行われる可能性があるようです。ただし、この変数の宣言が欠落しているため、その使用法/実装は不明です。この変数に複数のスレッドが同時にアクセスするのを防ぐロックがある場合、複数のスレッドがこのデータから相互にロックアウトする可能性があり、パフォーマンスがさらに低下します。dsdMain
于 2012-07-27T15:38:13.750 に答える
0

スレッドが実行されると、特定のプロセッサで時間が与えられます。プロセッサよりも多くのスレッドがある場合、システムコンテキストはスレッドを切り替えて、すべてのアクティブなスレッドを処理する時間を取得します。コンテキストスイッチングは本当に高価です。プロセッサよりも多くのスレッドがある場合、CPU時間のほとんどはコンテキスト切り替えによって占められ、シングルスレッドソリューションをマルチスレッドソリューションよりも速く見せることができます。

あなたの例は、不確定な数のスレッドを開始することを示しています。コアよりも多くのエントリを返す場合SplitSeqFastaは、より多くのスレッドとコアを作成し、多くのコンテキストスイッチングを導入します。

スレッドの数を手動で調整するか、スレッド並列ライブラリやParallelクラスなどを使用して自動的に調整することをお勧めします。

于 2012-07-27T16:00:44.487 に答える