正如有人指出的那样,您需要准确检查瓶颈在哪里以及为什么要使用线程。
通过迁移到多线程,您确实有可能提高性能。但是,如果您使用每个线程更新相同的 DataTable,则您会受到 DataTable 的限制。一次只有一个线程可以写入 DataTable(您用锁控制),因此您基本上仍然按顺序处理。
另一方面,大多数数据库都是为多个连接而设计的,在多个线程上运行,并且已经为此目的进行了高度调整。如果您想仍然使用多个线程:让每个线程都有自己的数据库连接,并进行自己的处理。
现在,根据正在进行的处理类型,您的瓶颈可能在于打开和处理文件,而不是数据库更新。
一种拆分方法:
- 将所有要处理的文件名放入文件名队列中。
- 创建一个(或多个)线程来从文件名队列中提取项目,打开并解析和处理文件,并将结果推送到结果队列中。
- 让另一个线程从结果队列中获取结果,并将它们插入到数据库中。
这些可以同时运行......数据库不会更新,直到有东西要更新,并且会在此期间等待。
这种方法可以让您真正知道谁在等待谁。如果读取/处理文件部分很慢,请创建更多线程来执行此操作。如果插入数据库部分很慢,请创建更多线程来执行此操作。队列只需要同步即可。
所以,伪代码:
Queue<string> _filesToProcess = new Queue<string>();
Queue<string> _results = new Queue<string>();
Thread _fileProcessingThread = new Thread( ProcessFiles );
Thread _databaseUpdatingThread = new Thread( UpdateDatabase );
bool _finished = false;
static void Main()
{
foreach( string fileName in GetFileNamesToProcess() )
{
_filesToProcess.Enqueue( fileName );
}
_fileProcessingThread.Start();
_databaseUpdatingThread.Start();
// if we want to wait until they're both finished
_fileProcessingThread.Join();
_databaseUpdatingThread.Join();
Console.WriteLine( "Done" );
}
void ProcessFiles()
{
bool filesLeft = true;
lock( _filesToProcess ){ filesLeft = _filesToProcess.Count() > 0; }
while( filesLeft )
{
string fileToProcess;
lock( _filesToProcess ){ fileToProcess = _filesToProcess.Dequeue(); }
string resultAsString = ProcessFileAndGetResult( fileToProcess );
lock( _results ){ _results.Enqueue( resultAsString ); }
Thread.Sleep(1); // prevent the CPU from being 100%
lock( _filesToProcess ){ filesLeft = _filesToProcess.Count() > 0; }
}
_finished = true;
}
void UpdateDatabase()
{
bool pendingResults = false;
lock( _results ){ pendingResults = _results.Count() > 0; }
while( !_finished || pendingResults )
{
if( pendingResults )
{
string resultsAsString;
lock( _results ){ resultsAsString = _results.Dequeue(); }
InsertIntoDatabase( resultsAsString ); // implement this however
}
Thread.Sleep( 1 ); // prevents the CPU usage from being 100%
lock( _results ){ pendingResults = _results.Count() > 0; }
}
}
我很确定有办法让它变得“更好”,但它应该可以解决问题,这样您就可以读取和处理数据,同时将完整的数据添加到数据库中,并利用线程。
如果您希望另一个线程处理文件或更新数据库,只需创建一个新线程( MethodName ),然后调用 Start() 即可。
这不是最简单的例子,但我认为它很彻底。您正在同步两个队列,并且需要确保每个队列在访问之前都已锁定。您正在跟踪每个线程何时应该完成,并且您的数据在线程之间进行整理,但从未使用队列处理多次。
希望有帮助。