多线程高手来帮帮忙阿

lendylixt 2010-09-26 10:32:28
最近学习多线程的时候遇到了些困难,想请教请教各位达人
我想做一个文件遍历的程序,指定一个文件夹,然后遍历这个文件夹及子文件夹下的所有文件,把文件信息写入数据库
于是我写了下面这个类

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;
}
}


但是个人感觉,这个类不能当作指针来用,是不是应该用委托来做?
我也不知道,如何能让程序暂停一段时间,然后自动恢复?
希望各位高手帮忙修改补充一下我的程序
...全文
141 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
lendylixt 2010-09-27
  • 打赏
  • 举报
回复
我的思路是:
指定的根目录会起一个线程
二级目录遍历的时候会另其一个线程
三\四\五级也一样
层级越深,那么遍历它的线程生命周期越短
如果文件夹没有到6级甚至更高,
我的数据库连接应该够用
现在看起来用foreach的话,线程就过多无法控制了
谢谢大家指导
学习了
lendylixt 2010-09-26
  • 打赏
  • 举报
回复
关键
我还是想,能不能用异步的机制,来完成这项工作?
lendylixt 2010-09-26
  • 打赏
  • 举报
回复
可不可以用XML文件?
如果全都预读到内存里
我怕内存吃不消
xinbin1122 2010-09-26
  • 打赏
  • 举报
回复
没必要这么多线程吧
hupengcscs 2010-09-26
  • 打赏
  • 举报
回复
思路可以换下,这样线程开的太多。可以先找出所有文件的地址等所有信息,然后再写入数据库。
lendylixt 2010-09-26
  • 打赏
  • 举报
回复
开始的时候我是写在一个线程里,有一个函数就可以搞定

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;
}



这不是突然心血来潮,想用用多线程提高一下效率么
ztenv 2010-09-26
  • 打赏
  • 举报
回复
foreach (string strDPath in strDirPath) { cDir cD = new cDir(strDPath); //如果有子文件夹的话,另起一个线程,对子文件夹遍历 Thread initDFDB = new Thread(new ThreadStart(cD.funDir)); initDFDB.Start(); }
完全没有必要这样做,把遍历的代码写到一个线程去吧,这样不会导致界面假死;遍历后,把数据可以放在缓存,由另一线程去写数据库,其中注意两个线程的互斥问题;
伟大的兔子 2010-09-26
  • 打赏
  • 举报
回复
如果存在子文件夹就开线程,你这样无限迭代下去,最主要是CPU资源不够用了把。先不说数据库并发是怎么处理的,这样几乎无限制的线程使用,早就把数据库的连接池资源使用完了。你这样子操作显然不合理,而且.Net中执行一个线程,当线程执行完毕后,一般会自动销毁。也可以使用Abort方法来手动销毁,但如果线程中使用的资源没有完全销毁,Abort方法执行后,也不能保证线程被销毁。线程的管理非常混乱。
你可以这样子:首先一个线程来处理扫描,扫描的信息存入字典中,另外一个线程依次去取字典的数据。使用线程池无法控制扫描和取数据的顺序。
3000sunqin 2010-09-26
  • 打赏
  • 举报
回复
完全是多线程的滥用。
应该使用一个线程来遍历所有子文件夹,因为遍历子文件夹是需要访问硬盘的,而硬盘是比较慢的,所以此处使用多线程完全没有作用。
对于写入到数据库,可以放在另外一个线程中,这两个线程之间使用一个缓冲区来进行沟通。

例如:
创建一个泛型队列,启动遍历子文件夹线程和写入数据库线程,将遍历到的记录向队列中写所遍历到的内容;
建议每写一定个数的文件夹后,线程休眠一段时间,写入数据库线程每隔一段时间负责检查泛型队列中是否有数据,如果有数据,将所有的数据出队之后一起写入数据库。
飞阁 2010-09-26
  • 打赏
  • 举报
回复
支持lianshaohua
边城的刀声 2010-09-26
  • 打赏
  • 举报
回复
就算用多线程你也不应该用手动创建线程的方法,而应该用线程池来实现ThreadPool.QueueWorkerItem()
ztenv 2010-09-26
  • 打赏
  • 举报
回复
你可以把写数据库的放到另外一个线程,这样遍历线程与写数据库的线程互不影响,
ztenv 2010-09-26
  • 打赏
  • 举报
回复
你这是线程的滥用了,并不能提代效率,因为硬盘的速度是有限的,机械运动比较慢,这个在os里讲过吧?
lendylixt 2010-09-26
  • 打赏
  • 举报
回复
顶啊
有高手没?

110,537

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧