最近学习多线程的时候遇到了些困难,想请教请教各位达人
我想做一个文件遍历的程序,指定一个文件夹,然后遍历这个文件夹及子文件夹下的所有文件,把文件信息写入数据库
于是我写了下面这个类    class cDir
    {
        private string strCn = "Data Source=.;Initial Catalog=DFInfo;Persist Security Info=True;User ID=DFInfo;pwd=DFInfo";
        public string strPath;
        public cDir(string strPath)
        {
            this.strPath = strPath;
        }
        public void funDir()
        {
             //遍历文件夹
            string[] strDirPath = Directory.GetDirectories(strPath);
            string[] strFilePath = Directory.GetFiles(strPath);
            foreach (string strDPath in strDirPath)
            {
                cDir cD = new cDir(strDPath);
                 //如果有子文件夹的话,另起一个线程,对子文件夹遍历
                Thread initDFDB = new Thread(new ThreadStart(cD.funDir));
                initDFDB.Start();
            }
            foreach (string strFPath in strFilePath)
            {
                FileInfo fi = new FileInfo(strFPath);
                string strFileName = fi.Name;
                string strCreationTime = fi.CreationTime.ToString();
                string strLastWriteTime = fi.LastWriteTime.ToString();
                long lLength = fi.Length;
                initDB(strPath, strFileName, strCreationTime, strLastWriteTime, lLength);
            }
            return;
        }
        private void initDB(string strPath, string strFileName, string strCreationTime, string strLastWriteTime, long lLength)
        {
            //加入新数据
             string strSql = "insert into tbFile (Path,FileName,CreationTime,LastWriteTime,lLength) values (@Path,@FileName,@CreationTime,@LastWriteTime,@lLength)";
            SqlParameter[] para = { new SqlParameter("@Path", strPath), new SqlParameter("@FileName", strFileName), new SqlParameter("@CreationTime", strCreationTime), new SqlParameter("@LastWriteTime", strLastWriteTime), new SqlParameter("@lLength", lLength) };
            exeSql(strSql, para);
            //写入数据库完毕
        }
        private void exeSql(string strSql, SqlParameter[] para)
        {
            SqlConnection sc = new SqlConnection(strCn);
            SqlCommand scmd = new SqlCommand(strSql, sc);
            foreach (SqlParameter sp in para)
            {
                scmd.Parameters.Add(sp);
            }
            sc.Open();
            scmd.ExecuteNonQuery();
            scmd.Parameters.Clear();
            sc.Close();
            sc.Dispose();
        }
    }经过测试,发现如果是文件夹个数比较少并且自文件夹的层级也比较少的时候,速度很快就能写入数据
但是如果是大量的文件夹,线程起的太多,我的数据库的资源就不够用了
我的机器上装的是sqlserver2005标准版,并发数最多好像只有5个
如果是线程太多,就需要把数据库看成临界资源,是不是应该用到线程异步的技术了?
想过用一个计数类来收集线程数,如果线程数大于5个,暂时停止创建新线程    class cCount
    {
        public int intCount;
        public cCount(int intCount)
        {
            this.intCount = intCount;
        }
        public void add()
        {
            intCount++;
            return;
        }
        public void minus()
        {
            intCount--;
            return;
        }
    }
但是个人感觉,这个类不能当作指针来用,是不是应该用委托来做?
我也不知道,如何能让程序暂停一段时间,然后自动恢复?
希望各位高手帮忙修改补充一下我的程序

解决方案 »

  1.   

                 foreach (string strDPath in strDirPath)              {                  cDir cD = new cDir(strDPath);                   //如果有子文件夹的话,另起一个线程,对子文件夹遍历                  Thread initDFDB = new Thread(new ThreadStart(cD.funDir));                  initDFDB.Start();              } 
    完全没有必要这样做,把遍历的代码写到一个线程去吧,这样不会导致界面假死;遍历后,把数据可以放在缓存,由另一线程去写数据库,其中注意两个线程的互斥问题;
      

  2.   

    开始的时候我是写在一个线程里,有一个函数就可以搞定        private void funDir(string strPath)
            {
                string[] strDirPath = Directory.GetDirectories(strPath);
                string[] strFilePath = Directory.GetFiles(strPath);
                foreach (string strDPath in strDirPath)
                {
                    this.funDir(strDPath);
                }
                foreach (string strFPath in strFilePath)
                {
                    FileInfo fi = new FileInfo(strFPath);
                    string strFileName = fi.Name;
                    string strCreationTime = fi.CreationTime.ToString();
                    string strLastWriteTime = fi.LastWriteTime.ToString();
                    long lLength = fi.Length;
                    initDB(strPath, strFileName, strCreationTime, strLastWriteTime, lLength);
                }
                return;
            }这不是突然心血来潮,想用用多线程提高一下效率么
      

  3.   

    可不可以用XML文件?
    如果全都预读到内存里
    我怕内存吃不消
      

  4.   

    就算用多线程你也不应该用手动创建线程的方法,而应该用线程池来实现ThreadPool.QueueWorkerItem()
      

  5.   

    如果存在子文件夹就开线程,你这样无限迭代下去,最主要是CPU资源不够用了把。先不说数据库并发是怎么处理的,这样几乎无限制的线程使用,早就把数据库的连接池资源使用完了。你这样子操作显然不合理,而且.Net中执行一个线程,当线程执行完毕后,一般会自动销毁。也可以使用Abort方法来手动销毁,但如果线程中使用的资源没有完全销毁,Abort方法执行后,也不能保证线程被销毁。线程的管理非常混乱。
    你可以这样子:首先一个线程来处理扫描,扫描的信息存入字典中,另外一个线程依次去取字典的数据。使用线程池无法控制扫描和取数据的顺序。
      

  6.   

    我的思路是:
    指定的根目录会起一个线程
    二级目录遍历的时候会另其一个线程
    三\四\五级也一样
    层级越深,那么遍历它的线程生命周期越短
    如果文件夹没有到6级甚至更高,
    我的数据库连接应该够用
    现在看起来用foreach的话,线程就过多无法控制了
    谢谢大家指导
    学习了