1

Так что я пытаюсь сделать здесь:Как правильно использовать Async, ОЖИДАНИЕ и ManualResetEvents контролировать бесконечное время цикла

  1. Сделайте петлю двигателя и работу на объекте, если очередь не пуста.
  2. Если очередь пуста, я вызываю handresetevent, чтобы поток был спящим.
  3. Когда элемент добавлен, и цикл не активен, я задал метод handresetevent.
  4. Чтобы ускорить работу, я забираю почти 5 элементов из списка и выполняю операцию на них асинхронно и жду, пока все они закончатся.

Проблема:

  1. Четкие методы на двух списках, называются как только новый вызов AddToUpdateQueueMethod называется.
  2. В моей голове, когда я жду Task.WhenAll (задачи), поэтому поток должен ждать своего завершения, прежде чем двигаться вперед, поэтому ясность в списках должна вызываться только после Task.WhenAll (задачи) возвращается.

Что мне здесь не хватает, или что будет лучшим способом достичь этого.

public async Task ThumbnailUpdaterEngine() 
    { 
     int count; 
     List<Task<bool>> tasks = new List<Task<bool>>(); 
     List<Content> candidateContents = new List<Content>(); 
     while (true) 
     { 

      for (int i = 0; i < 5; i++) 
      { 
       Content nextContent = GetNextFromInternalQueue(); 
       if (nextContent == null) 
        break; 
       else 
        candidateContents.Add(nextContent); 

      } 

      foreach (var candidateContent in candidateContents) 
      { 
       foreach (var provider in interactionProviders) 
       { 
        if (provider.IsServiceSupported(candidateContent.ServiceType)) 
        { 
         Task<bool> task = provider.UpdateThumbnail(candidateContent); 
         tasks.Add(task); 
         break; 
        } 
       } 
      } 
      var results = await Task.WhenAll(tasks); 
      tasks.Clear(); 
      foreach (var candidateContent in candidateContents) 
      { 
       if (candidateContent.ThumbnailLink != null && !candidateContent.ThumbnailLink.Equals(candidateContent.FileIconLink, StringComparison.CurrentCultureIgnoreCase)) 
       { 
        Task<bool> task = DownloadAndUpdateThumbnailCache(candidateContent); 
        tasks.Add(task); 
       } 
      } 
      await Task.WhenAll(tasks); 

      //Clean up for next time the loop comes in. 
      tasks.Clear(); 
      candidateContents.Clear(); 

      lock (syncObject) 
      { 
       count = internalQueue.Count; 
       if (count == 0) 
       { 
        isQueueControllerRunning = false; 
        monitorEvent.Reset(); 
       } 
      } 
      await Task.Run(() => monitorEvent.WaitOne()); 


     } 
    } 

    private Content GetNextFromInternalQueue() 
    { 
     lock (syncObject) 
     { 
      Content nextContent = null; 
      if (internalQueue.Count > 0) 
      { 
       nextContent = internalQueue[0]; 
       internalQueue.Remove(nextContent); 
      } 
      return nextContent; 
     } 
    } 

    public void AddToUpdateQueue(Content content) 
    { 
     lock (syncObject) 
     { 
      internalQueue.Add(content); 
      if (!isQueueControllerRunning) 
      { 
       isQueueControllerRunning = true; 
       monitorEvent.Set(); 
      } 
     } 
    } 
+6

С TPL, вы почти никогда не нужно использовать 'ManualResetEvent' и такие вещи, как такие вещи, как' Task.Run (() = > monitorEvent.WaitOne()) ', если вы не имеете дело с каким-то устаревшим кодом. Посмотрите на TPL Dataflow, он предлагает множество возможностей для организации обработки конвейера. – Noseratio

+0

Что вы ищете, это ['BlockingCollection '] (https://msdn.microsoft.com/en-us/library/dd267312%28v=vs.110%29.aspx) –

ответ

1

Вы должны просто использовать поток данных TPL. Это актерская структура поверх TPL с поддержкой async. Используйте ActionBlock с async действием и MaxDegreeOfParallelism 5:

var block = new ActionBlock<Content>(
    async content => 
    { 
     var tasks = interactionProviders. 
      Where(provider => provider.IsServiceSupported(content.ServiceType)). 
      Select(provider => provider.UpdateThumbnail(content)); 
     await Task.WhenAll(tasks); 

     if (content.ThumbnailLink != null && !content.ThumbnailLink.Equals(
      content.FileIconLink, 
      StringComparison.CurrentCultureIgnoreCase)) 
     { 
      await DownloadAndUpdateThumbnailCache(content); 
     } 
    }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5}); 

foreach (var content in GetContent()) 
{ 
    block.Post(content); 
} 

block.Complete(); 
await block.Completion 
+0

Так что это позаботится внутренних элементов цикла while, но как я могу сделать цикл while, когда очередь пуста, и только просыпаться, когда в очереди есть что-то. Я могу использовать wait.Sleep (someTimeout), но это не оптимально. Код выше, кроме инициализации блока, будет проходить внутри цикла while, но как я могу управлять потоком цикла while. –

+0

@ Jack_2060 Вам не нужно. TPL Dataflow обрабатывает все, что для вас. У него есть 5 задач, которые внутренне запускают делегат на вашем содержимом, а когда они закончены и очередь пуста, задача завершается. В следующий раз, когда вы опубликуете блок, будет создана новая задача и так далее. – i3arnon

Смежные вопросы