2016-01-08 3 views
0

Я пробовал много разных способов заставить это работать, и я уверен, что это неправильный способ подключить асинхронный/ждущий многопоточность. Вот что я до сих пор. Это ходок для каталогов, который я попытался сделать async. Я знаю, что вы не видите никаких асинхронных или ожидающих ключевых слов, и это потому, что я не увенчался успехом, но это то, что я пытаюсь сделать. Сейчас он запускается в консольном приложении, но позже я буду абстрагироваться и реорганизоваться, как только получаю рабочий POC. Любые рекомендации приветствуются.Async Await - Нужно руководство

static void RunProgram(CancellationToken ct) 
    { 
     try 
     { 
      foreach (var dir in _directoriesToProcess) 
      { 
       var newTask = CreateNewTask(dir, ct); 
       _tasks.Add(newTask); 
      } 

      while (_tasks.Count > 0) 
      { 
       lock (_collectionLock) 
       { 
        var t = _tasks.Where(x => x.IsCompleted == true).ToList(); 
        if (t != null) 
         foreach (var task in t) 
         { 
          _tasks.Remove(task); 
         } 
       } 
      } 

      OutputFiles(); 
      StopAndCleanup(); 
     } 
     catch (Exception ex) 
     { 
      Log(LogColor.Red, "Error: " + ex.Message, false); 
      _cts.Cancel(); 
     } 
    } 


    static Task CreateNewTask(string Path, CancellationToken ct) 
    { 
     return Task.Factory.StartNew(() => GetDirectoryFiles(Path, ct), ct); 
    } 

    static void GetDirectoryFiles(string Path, CancellationToken ct) 
    { 
     if (!ct.IsCancellationRequested) 
     { 
      List<string> subDirs = new List<string>(); 
      int currentFileCount = 0; 
      try 
      { 
       currentFileCount = Directory.GetFiles(Path, _fileExtension).Count(); 
       subDirs = Directory.GetDirectories(Path).ToList(); 

       lock (_objLock) 
       { 
        _overallFileCount += currentFileCount; 
        Log(LogColor.White, "- Current path: " + Path); 
        Log(LogColor.Yellow, "-- Sub directory count: " + subDirs.Count); 
        Log(LogColor.Yellow, "-- File extension: " + _fileExtension); 
        Log(LogColor.Yellow, "-- Current count: " + currentFileCount); 
        Log(LogColor.Red, "-- Running total: " + _overallFileCount); 
        _csvBuilder.Add(string.Format("{0},{1},{2},{3}", Path, subDirs.Count, _fileExtension, currentFileCount)); 
        Console.Clear(); 
        Log(LogColor.White, "Running file count: " + _overallFileCount, false, true); 
       } 

       foreach (var dir in subDirs) 
       { 
        lock (_collectionLock) 
        { 
         var newTask = CreateNewTask(dir, ct); 
         _tasks.Add(newTask); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       Log(LogColor.Red, "Error: " + ex.Message, false); 
       _cts.Cancel(); 
      } 
     } 
    } 
+1

Похоже, C# - рассмотреть добавив этот тег. –

+1

Насколько я знаю, нет асинхронных API для перечисления файловой системы. Даже если бы вы были, если вы не работаете над SSD (или подобным), распараллеливание сделает его медленнее и наложит ненужный стресс на диск. –

ответ

1

Я не думаю, что есть любая проблема с тем, что вы пытаетесь сделать, просто будьте осторожны в отношении неконтролируемого параллелизма, например чтение слишком большого количества каталогов сразу на разных потоках. Контекстное переключение может привести к замедлению работы.

Вместо того чтобы делать что-то в качестве побочных эффектов в своих методах, попробуйте вернуть собранные значения. например

static async Task<IEnumerable<DirectoryStat>> GetDirectoryFiles(string path, string fileExtension, CancellationToken ct) 
{ 
    var thisDirectory = await Task.Run(() => /* Get directory file count and return a DirectoryStat object */); 
    var subDirectoriesResults = await Task.WhenAll(Directory.GetDirectories(path).Select(dir => GetDirectoryFiles(dir, fileExtension, ct))); 

    return (new[] { thisDirectory }).Concat(subDirectoryResults); 
} 

Вы можете перебирать их позже, и вытащить нужные данные из DirectoryStat (и суммировать ваши счетчики файлов в соответствии с _overallFileCount и т.д.)

ПРИМЕЧАНИЕ: Непроверенные :)

+0

Это больше в отношении того, что я искал. Благодаря! – Edd

1

Вы можете запустить Synchronous Code Async с Task.Run(() => { //code }); также изменить тип возвращаемых в Task так что вы можете await его я бы переписать ваш код следующим образом:

static void RunProgram(CancellationToken ct) 
{ 
    try 
    { 
     foreach (var dir in _directoriesToProcess) 
     { 
      var newTask = CreateNewTask(dir, ct); 
      _tasks.Add(newTask); 
     } 

     //change your while so it does not execute all the time 
     while (_tasks.Count > 0) 
     { 
      lock (_collectionLock) 
      { 
       var tsk = _tasks.FirstOrDefault(); 
         if (tsk != null) 
         { 
          if (tsk.Status <= TaskStatus.Running) 
           await tsk; 
          _tasks.Remove(tsk); 
         } 
      } 
     } 

     OutputFiles(); 
     StopAndCleanup(); 
    } 
    catch (Exception ex) 
    { 
     Log(LogColor.Red, "Error: " + ex.Message, false); 
     _cts.Cancel(); 
    } 
} 


static Task CreateNewTask(string Path, CancellationToken ct) 
{ 
    return Task.Factory.StartNew(() => GetDirectoryFiles(Path, ct), ct); 
} 

//always use Task (or Task<T>) as return so you can await the process 
static async Task GetDirectoryFiles(string Path, CancellationToken ct) 
{ 
    if (!ct.IsCancellationRequested) 
    { 
     //Insert Magic 
     await Task.Run(() => { 
      List<string> subDirs = new List<string>(); 
      int currentFileCount = 0; 
      try 
      { 
       currentFileCount = Directory.GetFiles(Path, _fileExtension).Count(); 
       subDirs = Directory.GetDirectories(Path).ToList(); 

       lock (_objLock) 
       { 
        _overallFileCount += currentFileCount; 
        Log(LogColor.White, "- Current path: " + Path); 
        Log(LogColor.Yellow, "-- Sub directory count: " + subDirs.Count); 
        Log(LogColor.Yellow, "-- File extension: " + _fileExtension); 
        Log(LogColor.Yellow, "-- Current count: " + currentFileCount); 
        Log(LogColor.Red, "-- Running total: " + _overallFileCount); 
        _csvBuilder.Add(string.Format("{0},{1},{2},{3}", Path, subDirs.Count, _fileExtension, currentFileCount)); 
        Console.Clear(); 
        Log(LogColor.White, "Running file count: " + _overallFileCount, false, true); 
       } 

       foreach (var dir in subDirs) 
       { 
        lock (_collectionLock) 
        { 
         var newTask = CreateNewTask(dir, ct); 
         _tasks.Add(newTask); 
        } 
       } 
      }); 
     } 
     catch (Exception ex) 
     { 
      Log(LogColor.Red, "Error: " + ex.Message, false); 
      _cts.Cancel(); 
     } 
    } 
} 
+0

Я действительно надеялся получить помощь при использовании Task.WaitAll/Task.When Использование блокирующего объекта замедляет ходунок. – Edd