Во-первых, в Travel()
есть ошибка, когда вы ставите в очередь работу пула потоков для каждого каталога. Вы захватываете d
в лямбде, но ко времени запуска лямбды d
, вероятно, всегда будет последним путем в коллекции dirs
. Вот исправление для этого:
foreach ( var d in dirs )
{
var d2 = d;
ThreadPool.QueueUserWorkItem( o => Travel( d2, nesting - 1, cdown ) );
}
Кроме того, вы создаете CountdownEvent
для каждого каталога на вашем диске, что довольно дорого. Фактически, CountdownEvent
в TravelSync
является избыточным, так как это выполняется синхронно. Вы можете просто избавиться от них:
static void TravelSync(string path, CountdownEvent cd)
{
var dirs = Directory.GetDirectories(path);
//var cdown = new CountdownEvent(dirs.Length);
// this is normal synchronous code
foreach (var d in dirs)
TravelSync(d, null);
//cdown.Wait();
if ( cd != null ) cd.Signal();
}
Если вы используете .NET 4.0, вы также можете очистить Travel()
, используя Tasks
:
...
else
{
Messages.Add( path );
Directories.Add( path );
try
{
var dirs = Directory.GetDirectories( path );
var tasks = dirs.Select(
d => Task.Factory.StartNew(
() => Travel( d, nesting - 1, null )
)
).ToArray();
Task.WaitAll( tasks );
foreach ( var t in tasks ) t.Dispose();
}
catch ( Exception x )
{
...
}
}
Конечно, коллекции Messages
и Directories
должны быть поточно-ориентированными.
РЕДАКТИРОВАТЬ: На самом деле, PLINQ делает это еще проще:
Parallel.ForEach( dirs, d => Travel( d, nesting - 1, null ) );