2012-07-27 111 views
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分钟后杀死它)。

我的执行有问题吗?如何加快速度?

谢谢。

+0

SearchAlgorithm.SearchInBothDirections是做什么的? – 2012-07-27 15:24:31

+0

使用类似DotTrace的分析器,它会告诉你时间消耗在哪里。 – 2012-07-27 15:26:17

+0

@ Bryan:SearchAlgorithm.SearchInBothDirections正在对给定字符串进行深入搜索,返回两个候选清单列表作为输出参数 – Mavershang 2012-07-27 15:29:30

回答

0

多线程之前的代码是什么?很难说这个代码在做什么,很多“工作”代码似乎隐藏在搜索算法中。然而,一些想法:

  1. 你提到的“输入文件”,但是这并没有明确用代码显示 - 如果你的文件访问被线程,这不会提高性能的文件访问将成为瓶颈。
  2. 创建比您拥有的线程多的CPU内核将最终降低性能(除非每个线程都被阻塞等待不同的资源)。在你的情况下,我会建议总共8个线程太多。
  3. 似乎很多数据(内存)访问可能通过您的类DescrStrDetail完成,该类从您的Main方法中的变量dsd传递给每个子线程。然而,这个变量的声明丢失了,所以它的使用/实现是未知的。如果此变量具有阻止多个线程同时访问的锁定,那么您的多个线程可能会将这些数据锁定在其他位置,从而进一步降低性能。
0

当线程运行时,它们在特定的处理器上被赋予时间。如果线程数量多于处理器,则系统上下文会在线程之间切换,以便在一段时间内处理所有活动的线程。上下文切换是真的很贵。如果线程数多于处理器数,大部分CPU时间可以通过上下文切换占用,并且使单线程解决方案比多线程解决方案更快速地看

你的例子显示开始不确定的线程数。如果SplitSeqFasta返回的内容比内核更多,则将创建更多线程和内核,并引入大量上下文切换。

我建议你手动节制线程的数量,或者使用线程并行库和Parallel类之类的东西来让它自动为你加油。

3

在我看来,你正在尝试与多个线程并行处理文件。假设你有一个机械磁盘,这是一个坏主意。

基本上,磁盘头部需要为每个读取请求寻找下一个读取位置。这是一个代价高昂的操作,并且由于多个线程发出读取命令,这意味着在每个线程轮到它运行时头部会被反弹。与单线程读取数据的情况相比,这会显着降低性能。