最近学习多线程的时候遇到了些困难,想请教请教各位达人
我想做一个文件遍历的程序,指定一个文件夹,然后遍历这个文件夹及子文件夹下的所有文件,把文件信息写入数据库
于是我写了下面这个类 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;
}
}
但是个人感觉,这个类不能当作指针来用,是不是应该用委托来做?
我也不知道,如何能让程序暂停一段时间,然后自动恢复?
希望各位高手帮忙修改补充一下我的程序
我想做一个文件遍历的程序,指定一个文件夹,然后遍历这个文件夹及子文件夹下的所有文件,把文件信息写入数据库
于是我写了下面这个类 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;
}
}
但是个人感觉,这个类不能当作指针来用,是不是应该用委托来做?
我也不知道,如何能让程序暂停一段时间,然后自动恢复?
希望各位高手帮忙修改补充一下我的程序
完全没有必要这样做,把遍历的代码写到一个线程去吧,这样不会导致界面假死;遍历后,把数据可以放在缓存,由另一线程去写数据库,其中注意两个线程的互斥问题;
{
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;
}这不是突然心血来潮,想用用多线程提高一下效率么
如果全都预读到内存里
我怕内存吃不消
你可以这样子:首先一个线程来处理扫描,扫描的信息存入字典中,另外一个线程依次去取字典的数据。使用线程池无法控制扫描和取数据的顺序。
指定的根目录会起一个线程
二级目录遍历的时候会另其一个线程
三\四\五级也一样
层级越深,那么遍历它的线程生命周期越短
如果文件夹没有到6级甚至更高,
我的数据库连接应该够用
现在看起来用foreach的话,线程就过多无法控制了
谢谢大家指导
学习了