Não se enganem muito pelo exemplo. Neste artigo, o autor usa Task e Thread no mesmo lugar, e não são a mesma coisa, por mais que comportamentos parecidos. Um possui um pool gerenciado pelo Runtime, mais eficiente para operações assíncronas e tarefas no mesmo contexto, o outro é gerenciado pelo sistema operacional, onde o contexto varia um pouco mais e a conversação entre threads tem que ser feita com cuidado.

Parallel.For tem poucos usos se souber usar bem. Se entender a fundo, entenderá que tarefas assíncronas não podem travar objetos com synclock, no caso é usado semáforos, mas reduzindo a performance geral.

Colocar lock (objeto) em outro Thread nem sempre é a melhor resolução para seu problema. O .NET oferece o ConcurrentBag<T>, ConcurrentStack, ConcurrentSeiLáOque para quase tudo o que você precisa, implementações prontas para serem usadas por mais de um thread.

Recomendo ler as diferenças entre Task e Threads, pode ajudar a entender o que quero dizer.

opa, a ideia era mostrar algumas formas de implementar paralelismo e o desempenho de cada um e não entrar no detalhe do processamento.

E sobre o lock, essa afirmação sua é um mito generalizado, eu fiz os testes com e sem lock e não mudou o desempenho, não posso ensinar paralelismo sem ensinar lock, pq se não pra muitos casos nem vai atender. Muitos casos vão precisar proteger alguma variável...

`lock` não é possível ser feito em contexto assíncrono. Você precisará usar semáforos para fazer isso. Synclock naturalmente tem um desempenho melhor que semáforos em um contexto síncrono, mas em contextos assíncronos você não tem essa opção.