visual una studio standard programa para net librerias hacer framework crear como clases clase bibliotecas biblioteca c# multithreading .net-4.0 task-parallel-library multitasking

c# - studio - ¿El uso de la biblioteca de Tareas(TPL) hace que una aplicación sea multiproceso?



librerias de visual studio 2017 (4)

Recientemente al ser entrevistado, me llegó esta pregunta.

P: ¿Has escrito aplicaciones multiproceso?

A: si

P: ¿Te importa explicar más?

R: Utilicé Tasks (biblioteca paralela de tareas) para realizar algunas tareas, como waiting for some info from internet while loading UI . Esto mejora la usabilidad de mi aplicación.

P: Pero, solo que ha utilizado TPL significa que ha escrito una aplicación de multithreaded ?

Yo: (No estoy seguro de qué decir 1)

Entonces, ¿qué es exactamente una aplicación multi-hilo? ¿Es diferente de usar Tasks ?


P: Pero, solo que ha utilizado TPL, ¿significa que ha escrito una aplicación de multiproceso?

Pregunta inteligente, Tarea! = Multiproceso, utilizando TaskCompletionSource puede crear una Task que puede ejecutarse en un solo hilo (puede ser solo un hilo UI).

Task es solo una abstracción sobre una operación que puede completarse en el futuro. No significa que el código sea multiproceso. Por lo general, la Task implica subprocesos múltiples, no necesariamente siempre.

Y tenga en cuenta que solo con el conocimiento de TPL no puede decir que conoce subprocesos múltiples. Hay muchos conceptos que necesitas cubrir.

  • Hilo
  • Primitivas de sincronización
  • Seguridad del hilo
  • Programación asíncrona
  • Programación paralela que forma parte de TPL.
  • y mucho mas ...

y por supuesto la biblioteca paralela de tareas también.

Nota: esta no es la lista completa, estos son solo de la parte superior de mi cabeza.

Recursos para aprender:

Solo para enhebrar, sugiero http://www.albahari.com/threading/

Para videos tutoriales te sugiero Pluralsight . Se paga pero vale la pena el costo.

Por último, pero no menos importante: sí, por supuesto, es .


Las tareas se pueden usar para representar operaciones que tienen lugar en varios subprocesos, pero no tienen que hacerlo. Uno puede escribir aplicaciones TPL complejas que solo se ejecutan en un solo hilo. Cuando tiene una tarea que, por ejemplo, representa una solicitud de red para algunos datos, esa tarea no creará subprocesos adicionales para lograr ese objetivo. Tal programa es (con suerte) asíncrono, pero no necesariamente mutlithreaded.

El paralelismo es hacer más de una cosa al mismo tiempo. Esto puede o no ser el resultado de múltiples hilos.

Vayamos con una analogía aquí.

Aquí es cómo Bob cocina la cena:

  1. Llena una olla de agua y la hierve.
  2. Luego pone la pasta en el agua.
  3. Él drena la pasta cuando está hecha.
  4. Prepara los ingredientes para su salsa.
  5. Pone todos los ingredientes para su salsa en una cacerola.
  6. Él cocina su salsa.
  7. Él pone su salsa en su pasta.
  8. El come la cena

Bob ha cocinado de forma totalmente sincrónica, sin subprocesos múltiples, asincronía o paralelismo al cocinar su cena.

Así es como Jane cocina la cena:

  1. Ella llena una olla de agua y comienza a hervirla.
  2. Ella prepara los ingredientes para su salsa.
  3. Ella pone la pasta en el agua hirviendo.
  4. Ella pone los ingredientes en la cacerola.
  5. Ella drena su pasta.
  6. Ella pone la salsa en su pasta.
  7. Ella come su cena.

Jane aprovechó la cocina asíncrona (sin subprocesos múltiples) para lograr un paralelismo al cocinar su cena.

Así es como Servy cocina la cena:

  1. Él le dice a Bob que hierva una olla con agua, ponga la pasta cuando esté lista y sirva la pasta.
  2. Él le dice a Jane que prepare los ingredientes para la salsa, la cocine y luego la sirva sobre la pasta cuando haya terminado.
  3. Espera a que Bob y Jane terminen.
  4. Él come su cena.

Servy aprovechó varios subprocesos (trabajadores), cada uno de los cuales hizo su trabajo de forma síncrona, pero que trabajó de forma asíncrona entre sí para lograr el paralelismo.

Por supuesto, esto se vuelve aún más interesante si consideramos, por ejemplo, si nuestra estufa tiene dos quemadores o solo uno. Si nuestra estufa tiene dos quemadores, entonces nuestros dos hilos, Bob y Jane, son capaces de hacer su trabajo sin meterse demasiado entre ellos. Es posible que se toquen un poco, o intenten agarrar algo del mismo gabinete de vez en cuando, por lo que cada uno se ralentizará un poco , pero no mucho. Si cada uno de ellos necesita compartir un solo quemador de la estufa, entonces no podrán hacer mucho cuando la otra persona está trabajando. En ese caso, el trabajo no se realizará más rápido que tener a una persona cocinando de forma completamente sincrónica, como lo hace Bob cuando está solo. En este caso, estamos cocinando con varios hilos, pero nuestra cocina no está en paralelo . No todo trabajo multiproceso es en realidad trabajo paralelo . Esto es lo que sucede cuando se ejecutan varios subprocesos en una máquina con una CPU. En realidad, no hace el trabajo más rápido que solo usando un hilo, ya que cada hilo solo toma turnos para hacer el trabajo. (Eso no significa que los programas multiproceso no tengan sentido en las CPU de un núcleo, no lo son, es solo que la razón para usarlos no es mejorar la velocidad).

Incluso podemos considerar cómo estos cocineros harían su trabajo utilizando la Biblioteca paralela de tareas, para ver qué usos del TPL corresponden a cada uno de estos tipos de cocineros:

Así que primero tenemos bob, solo escribimos código normal no TPL y hacemos todo de forma sincrónica:

public class Bob : ICook { public IMeal Cook() { Pasta pasta = PastaCookingOperations.MakePasta(); Sauce sauce = PastaCookingOperations.MakeSauce(); return PastaCookingOperations.Combine(pasta, sauce); } }

Luego tenemos a Jane, que inicia dos operaciones asíncronas diferentes, y luego espera a ambas después de comenzar cada una de ellas para calcular su resultado.

public class Jane : ICook { public IMeal Cook() { Task<Pasta> pastaTask = PastaCookingOperations.MakePastaAsync(); Task<Sauce> sauceTask = PastaCookingOperations.MakeSauceAsync(); return PastaCookingOperations.Combine(pastaTask.Result, sauceTask.Result); } }

Como recordatorio aquí, Jane está usando el TPL y está haciendo gran parte de su trabajo en paralelo, pero solo está usando un solo hilo para hacer su trabajo.

Luego tenemos a Servy, que usa Task.Run para crear una tarea que representa hacer trabajo en otro hilo . Inicia dos trabajadores diferentes, hace que ambos trabajen en forma sincrónica y luego espera que ambos trabajadores terminen.

public class Servy : ICook { public IMeal Cook() { var bobsWork = Task.Run(() => PastaCookingOperations.MakePasta()); var janesWork = Task.Run(() => PastaCookingOperations.MakeSauce()); return PastaCookingOperations.Combine(bobsWork.Result, janesWork.Result); } }


Mis 5 centavos: no tiene que participar en los subprocesos explícitamente con Task.Run o Task.Factory.StartNew para hacer que su aplicación TPL sea multiproceso. Considera esto:

async static Task TestAsync() { Func<Task> doAsync = async () => { await Task.Delay(1).ConfigureAwait(false); Console.WriteLine(new { Thread.CurrentThread.ManagedThreadId }); }; var tasks = Enumerable.Range(0, 10).Select(i => doAsync()); await Task.WhenAll(tasks); } // ... TestAsync().Wait();

El código después de await dentro de doAsync se ejecuta simultáneamente en diferentes subprocesos. De manera similar, la concurrencia se puede introducir con la API de sockets asíncronos, HttpClient , Stream.ReadAsync o cualquier otra cosa que use el conjunto de subprocesos (incluidos los subprocesos del conjunto IOCP).

Hablando en sentido ThreadPool , cada aplicación .NET ya está multiproceso, porque el Framework usa ThreadPool ampliamente. Incluso una aplicación de consola simple mostrará más de un hilo para System.Diagnostics.Process.GetCurrentProcess().Threads.Count . Su entrevistador debería haberle preguntado si ha escrito un código concurrente (o paralelo).


Una Task es una promesa para el trabajo futuro que se completará. Al usarlo, puede usarlo para trabajos I/O based , lo que no requiere que use varios subprocesos para la ejecución del código. Un buen ejemplo es el uso de la función C # 5 de async/await con HttpClient que hace trabajo de E / S basado en la red.

Sin embargo, puede aprovechar la TPL para realizar trabajos de subprocesos múltiples. Por ejemplo, cuando usa Task.Run o Task.Factory.Startnew para comenzar una nueva tarea, el trabajo detrás de escena se pone en cola para usted en el ThreadPool , que el TPL abstrae, lo que le permite usar varios subprocesos.

Un escenario común para el uso de varios subprocesos es cuando tiene trabajo enlazado a la CPU que se puede hacer simultáneamente (en paralelo). Trabajar con una aplicación multiproceso conlleva una gran responsabilidad.

Así que vemos que trabajar con la TPL no es necesario usar múltiples subprocesos, pero definitivamente puedes aprovecharla para hacer subprocesos múltiples.