A primeira é uma opção muito melhor.
Parallel.ForEach, internamente, usa a Partitioner<T>
para distribuir sua coleção em itens de trabalho. Ele não executará uma tarefa por item, mas fará o lote para reduzir a sobrecarga envolvida.
A segunda opção agendará um único Task
por item em sua coleção. Embora os resultados sejam (quase) os mesmos, isso apresentará muito mais sobrecarga do que o necessário, especialmente para coleções grandes, e fará com que os tempos de execução gerais sejam mais lentos.
FYI - O Partitioner usado pode ser controlado usando as sobrecargas apropriadas para Parallel.ForEach , se desejado. Para detalhes, consulte Particionadores personalizados no MSDN.
A principal diferença, em tempo de execução, é a segunda que será assíncrona. Isso pode ser duplicado usando Parallel.ForEach, fazendo o seguinte:
Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
Ao fazer isso, você ainda aproveita os particionadores, mas não bloqueia até que a operação esteja concluída.
Eu fiz um pequeno experimento de execução do método "1.000.000.000 (um bilhão)" de vezes com "Parallel.For" e um com objetos "Task".
Eu medi o tempo do processador e achei o Parallel mais eficiente. Parallel.For divide sua tarefa em pequenos itens de trabalho e os executa em todos os núcleos paralelamente da maneira ideal. Ao criar muitos objetos de tarefa (o FYI TPL utilizará o pool de threads internamente), cada execução será executada em cada tarefa, criando mais estresse na caixa, o que é evidente no experimento abaixo.
Também criei um pequeno vídeo que explica o TPL básico e também demonstrou como o Parallel.For utiliza seu núcleo com mais eficiência http://www.youtube.com/watch?v=No7QqSc5cl8 em comparação com tarefas e threads normais.
Experiência 1
Experiência 2
fonte
Mehthod1()
faz neste exemplo?O Parallel.ForEach otimizará (pode nem mesmo iniciar novos encadeamentos) e bloqueará até que o loop seja concluído, e o Task.Factory criará explicitamente uma nova instância de tarefa para cada item e retornará antes que eles sejam concluídos (tarefas assíncronas). Parallel.Foreach é muito mais eficiente.
fonte
Na minha opinião, o cenário mais realista é quando as tarefas têm uma operação pesada para concluir. A abordagem de Shivprasad se concentra mais na criação de objetos / alocação de memória do que na própria computação. Fiz uma pesquisa chamando o seguinte método:
A execução deste método leva cerca de 0,5 segundo.
Liguei 200 vezes usando o Parallel:
Então eu liguei 200 vezes usando o modo antiquado:
Primeiro caso concluído em 26656ms, o segundo em 24478ms. Eu repeti isso muitas vezes. Sempre que a segunda abordagem é marginalmente mais rápida.
fonte