多线程速度问题

时间:2012-07-27 15:21:17

标签: c# multithreading

我在代码中添加了多线程部分。

 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分钟后杀死它)。

我的实施有问题吗?如何加快速度?

感谢。

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

多线程之前的代码是什么?很难说出这段代码在做什么,而且很多“工作”代码似乎都隐藏在搜索算法中。不过,有些想法:

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

答案 2 :(得分:0)

当线程运行时,它们会在特定处理器上获得时间。如果线程多于处理器,则系统上下文在线程之间切换,以使所有活动线程有一段时间进行处理。上下文切换非常昂贵。如果线程多于处理器,则大多数CPU时间可以通过上下文切换来占用,并使单线程解决方案比多线程解决方案更快

您的示例显示了启动不确定数量的线程。如果SplitSeqFasta返回的条目数多于核心数,则会创建更多的线程和核心,并引入大量的上下文切换。

我建议您手动限制线程数,或者使用线程并行库和Parallel类之类的东西让它自动为您节流。