对多线程刚入手,请教达人!
有一程序中有大耗时计算任务,在主线程中计算估计耗时数十小时。
有一8核服务器,打算利用其多核特点,开多线程,提高效率,但是没有明显改善。
在任务分解上没有问题。开了两个专用于计算的线程,但是发现cpu占用率还没有使用没有使用单线程的时候高。
我知道开多线程不会是两个线程就是原来的一半,三个就是原来的三分之一的关系,但是耗费的时间和原单线程相差无几。 
大家能否帮助我分析一下原因。对了开的用于计算的线程优先级订到了最高。
开的线程是并行的。不涉及资源问题。各自使用自己资源。没有锁的问题
开始线程之前,建了两个同一个类的对象,然后再开两个线程,运行的分别是两个对象的同一个方法.他们之间不涉及资源问题。
两个线程对同一个数据库同一张表作不同的查询,返回结果,各个线程处理自己的查询的结果。
关键代码如下:
在public partial class Form1 : Form
    {

private void button2_Click(object sender, EventArgs e)
        {
            
                 // 这是两个用于计算的对象。
                DealData    MyDeal = new DealData(iFace.NetName, iFace.TimeSpanType);
                DealData    MyDeal1 = new DealData(iFace.NetName, iFace.TimeSpanType);                    MyDeal.MyData = new OutPutData(iFace.NodeNum, iFace.SectionNum, 1);
                    MyDeal1.MyData = new OutPutData(iFace.NodeNum, iFace.SectionNum, 1);
                    //用于计算的参数,在Deal中使用。
                    MyDeal.Time1 = new DateTime(2008, 1, 1);
                    MyDeal.Time2 = new DateTime(2008, 7, 1);
                    MyDeal1.Time1 = new DateTime(2008, 7, 1);
                    MyDeal1.Time2 = new DateTime(2009, 1, 1);
                   //开两个线程
                    System.Threading.Thread newThread;
                    newThread = new System.Threading.Thread(MyDeal.Deal);
                    System.Threading.Thread newThread1;
                    newThread1 = new System.Threading.Thread(MyDeal1.Deal);
                    newThread.Priority = ThreadPriority.Highest;
                    newThread1.Priority = ThreadPriority.Highest;
                    newThread.Start();
                    newThread1.Start();               
        }        
 class DealData
    {   //用于放参数
        public DateTime Time1,Time2;
        public void Deal()
        {            
            //ConString是已知的
            SqlConnection connection = new SqlConnection(ConString);
            SqlCommand command = new SqlCommand("FindinTimeGap", connection);
            command.CommandType = CommandType.StoredProcedure;
            SqlParameter parameter1 = command.Parameters.Add("@timeentry", SqlDbType.DateTime);
            SqlParameter parameter2 = command.Parameters.Add("@timeexit", SqlDbType.DateTime);
            connection.Open();
            parameter1.Value = Time1;
            parameter2.Value = Time2;
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                try
                {
                    长耗时计算部分
                }
                catch
                {
                    。
                };
            };
            reader.Close();
            connection.Close();
        }

解决方案 »

  1.   

    你的是什么系统?我双核,XP SP2的时候,不安装多核补丁,CPU占有率也一直只有50%。安装后,多线程循环,就能够到98%~100%。
    跟操作系统也有关系的。
      

  2.   

      while (reader.Read()) //感觉在这里
      

  3.   

    根据你的CPU去下载吧,我过去在哪里下的自己也忘记了。GOOGLE一下全来了。
    服务器的话,还是安装2003比较好吧,XP感觉还是不够~~~
      

  4.   

    建议你多开几个线程,但不要太多,像你这种情况8核,由于调用了外部的数据库,可以开到50-80个,看是否会有效果一般一个cpu支持25个线程比较好,除去进程本身需要的进程,一般建议每cpu开到20个线程的样子,当然如果单纯的不访问外部资源(这种情况下可能会被外部资源阻塞,比如访问数据库),一般1个cpu开2个线程就够了。
      

  5.   

    之所以cpu不上去,是因为被数据库阻塞在那里了,你可以对于每个数据库的查询动作分解的更小,这样对服务器的cpu利用率就会高些,不然负载其实在数据库上了。
      

  6.   

    一个cpu开两个线程,基本不会切换线程,可以把内核损耗降到最低。如果你需要开非常多的线程,建议使用多个进程,每个进程里开15-20个线程的样子,这样效率会比较高。这些是我做多线程的一些经验,share出来以供参考。
      

  7.   


    你先多开几个线程试试不就有结果了?最近我也在搞系统性能的问题,也是8核cpu,压力一上来,就90%几了。线程绝不是越多越好,少了也没效率。
      

  8.   

    然后你可以对数据库进行优化,因为数据库查询很有可能是io操作,你的一个查询需要多长时间?如果需要10毫秒,你的线程就阻塞10毫秒,你可以测试下,用一个线程sleep1毫秒试试,cpu就不会上去。
      

  9.   

    你的8核的cpu的服务器有多大内存?4g有么?我的测试的进程的内存已经达到1g多了,能损耗多少资源呢?不要这么不相信操作系统,不相信服务器。
      

  10.   

    看你的代码就是一个datareader,还不是dataset,能有多少资源损耗呢?只会占用数据库连接,但数据库连接默认好像100个呢。
      

  11.   

    再看了一下你的代码,你可以用一个线程去读数据库,然后把那个标注为“长耗时间的计算”的代码再开子线程来做,你看看cpu能上去不?
      

  12.   

    不知道你的数据是否有顺序,如果有,你可以每次读取其中几千条到内存,然后分配index 范围给你的子线程,允许他们去处理这个范围内的数据,当所有都处理完了,住线程根据最后一条数据的大小再去获取几千条数据来处理,如此循环,知道全部处理完。AutoResetEvent events = new AutoResetEvent[15];int perThreadProcessCount = 100;
    DataView dataCollection = null;void MainThread()
    {
    int selectStartIndex = 0;//有顺序字段的起始值
    while(true)
    {
     dataCollection = GetData(conditon);//condition 为 select top 1500 *  from table where key > selectStartIndex
    if(dataCollection.Count <= 0)
    {
    break;
    }
    perThreadProcessCount = Math.Round(dataCollection.Count / events.Length,0);Thread[] thds = new Thread[events.Length];
    int perStartIndex = 0;
    for(int i = 0;i < thds.Length;i ++)
    {
    perStartIndex = perThreadProcessCount * i;
    events[i] = new AutoResetEvent(false);
    thds[i] = new Thread(delegate(){
    if(perStartIndex < dataCollection.Count)
    {
    for(int j = perStartIndex; j < perThreadProcessCount; j ++)
    {
    if(j < dataCollection.Count)
    {
    DataRowView drv = dataCollection[i];
    //处理数据
    }
    }
    }
    events[i].Set();
    }
    AutoResetEvent.WaitAll(events);
    selectStartIndex = Convert.ToInter32(dataCollection[dataCollection.Count -1][key]);
    }}大致就是这样了,因为手写的,可能有些语法或者括号位置不对,应该能读懂吧。
      

  13.   

    tmxk2002,谢谢了,我下午试试。
    再请教。
      

  14.   

    还有··两个线程··多核时不会给你分配资源·
    会再单核中执行,
    sdp081218,老兄,您这么说是为什么?
      

  15.   

    reader.Read() 是阻塞的吧。
    一般同一进程中的线程系统会优先考虑它们的亲缘性而尽量安排在同一个核心上运行,虽然你开了多线程,但是线程如果
    并不是总在忙的话,线程之间很可能都在同一个核心上被调度的。楼主要把真正的时间密集运算部分分离出来,调整一下
    任务分配。如果  while (reader.Read()) 的运行频率很高并且reader.Read() 是阻塞的,那么线程进入睡眠的时间就会很多,
    建议楼主考虑将reader.Read() 作为单独的任务与计算任务分离开来。可以开很多的reader.Read()线程,但是运算
    线程的数目只需和核心数目差不多应该就可以了,所有的reader.Read()线程的结果都提交给运算线程做运算
      

  16.   

    rulary 谢谢
    一般同一进程中的线程系统会优先考虑它们的亲缘性而尽量安排在同一个核心上运行,虽然你开了多线程,但是线程如果
    并不是总在忙的话,线程之间很可能都在同一个核心上被调度的。
    这些知识在哪有介绍?MSDN?