Pergunta

Quero saber qual a melhor maneira de processar os resultados de um processo de longa duração em série, mas em um tópico de baixa prioridade usando o .NET 4.0 Extensões paralelas.

Eu tenho a aula a seguir que faz a execução e fornece os resultados:

public class Step 
{
  public string Name { get; set; }
  public TimeSpan Duration { get; set; }
  public bool Completed { get; set; }

  public void Execute() 
  {
     DateTime before = DateTime.Now;
     RemotedService.DoSomeStuff();
     Duration = DateTime.Now - before;
     Completed = true;
  }
}

Como posso processar essas etapas e também salvá -las em um arquivo, para que sejam processadas? Eu gostaria de salvá -los em um arquivo enquanto RemotedService.DoSomeStuff() está aguardando uma resposta do servidor.

Escrever para o arquivo seria assim:

using (StreamWriter w = File.AppendText("myFile.txt"))
{
  var completedStep = completedSteps.Dequeue();
  w.WriteLine(string.Format("Completed {0} with result: {1} and duration {2}", 
                            completedStep.Name, 
                            completedStep.Completed, 
                            completedStep.Duration));
}

Uma opção que vem à mente é adicioná -los a um Queue e ter um Timer Isso os processa. Mas isso não aproveita o tempo de inatividade das chamadas remotas.

Outra opção que vem à mente é escrever assíncronos cada resultado no arquivo usando um System.Threading.Tasks.Task por Step, mas isso não garante que eles sejam salvos em ordem e também podem introduzir a contenção com a gravação do arquivo.

Foi útil?

Solução

Eu sugeriria criar um BlockingCollection<Step> (Vejo System.Collections.Concurrent espaço para nome). À medida que cada etapa é concluída, é adicionada a essa coleção. O comportamento padrão de BlockingCollection é funcionar como uma fila, para que você obtenha o comportamento do FIFO que está procurando.

Um segundo thread atende à fila, removendo cada item e gravando -o para um arquivo de log.

Então, se você adicionou a fila:

static private BlockingCollection<Step> LogQueue = new BlockingCollection<Step>();

Você adicionaria isso ao seu Execute Método, após a conclusão do item:

LogQueue.Add(this);

E seu tópico de registro, que você iniciaria no construtor estático:

static void LoggingThread()
{
    using (var w = new StreamWriter(...))
    {
        while (!LogQueue.IsCompleted())
        {
            Step item;
            if (LogQueue.TryTake(out item))
            {
                w.WriteLine(....);
            }
        }
    }
}

O tópico de registro como eu escrevi, usa um System.Threading fio. Pode haver uma maneira mais fácil ou melhor de fazê -lo com o TPL. Ainda não estou muito familiarizado com a TPL, então não poderia dizer.

Outras dicas

Uma abordagem é criar um agendador de tarefas personalizado (ver http://msdn.microsoft.com/en-us/library/ee789351.aspx). Seu agendador de tarefas personalizado pode limitar a simultaneidade a uma execução estrita em ordem.

Criar um agendador de tarefas também permite controlar a prioridade do thread, ou o ApartmentState, que pode ser desejável em algumas situações.

Você está literalmente descrevendo o caso de uso da Workflow Foundation - ele faz tudo isso para você :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top