¿Cuál es la diferencia entre task y thread?

378

En C # 4.0, tenemos Tasken el espacio de nombres System.Threading.Tasks . ¿Cuál es la verdadera diferencia entre Thready Task. Hice algún programa de muestra (ayuda tomada de MSDN) por mi propio bien de aprender con

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

pero tengo muchas dudas ya que la idea no es tan clara.

Inicialmente busqué en Stackoverflow un tipo similar de pregunta, pero es posible que con este título de pregunta no haya podido obtener la misma. Si alguien sabe sobre el mismo tipo de pregunta que se está publicando aquí anteriormente, amablemente proporcione la referencia del enlace.

hippietrail
fuente
8
los hilos ejecutan tareas
pm100

Respuestas:

315

Una tarea es algo que quieres hacer.

Un hilo es uno de los muchos posibles trabajadores que realiza esa tarea.

En términos de .NET 4.0, una tarea representa una operación asincrónica. Los subprocesos se utilizan para completar esa operación dividiendo el trabajo en trozos y asignándolos a subprocesos separados.

Trigo Mitch
fuente
¿Podría proporcionar un ejemplo rudimentario de hilos que trabajan para completar una tarea? No sé si los hilos están haciendo un trabajo independiente entre sí o si hacen algún cálculo de trabajo en equipo .
Pensum
Ambos escenarios son posibles: en una situación óptima, los hilos hacen un trabajo independiente sin la necesidad de sincronizar con otros hilos. En la práctica, los bloqueos se utilizan para coordinar hilos.
Mitch Wheat
451

En términos informáticos, a Taskes un futuro o una promesa . (Algunas personas usan esos dos términos de manera sinónimo, algunos los usan de manera diferente, nadie puede ponerse de acuerdo en una definición precisa ). Básicamente, una Task<T>"promesa" de devolverle un T, pero no ahora, cariño, estoy un poco ocupado, ¿por qué no? vuelves mas tarde?

A Threades una forma de cumplir esa promesa. Pero no todos Tasknecesitan un nuevo Thread. (De hecho, la creación de un subproceso a menudo no es deseable, porque hacerlo es mucho más costoso que reutilizar un subproceso existente del conjunto de subprocesos. Más sobre eso en un momento). Si el valor que está esperando proviene del sistema de archivos o un base de datos o la red, entonces no hay necesidad de un subproceso para sentarse y esperar los datos cuando pueden atender otras solicitudes. En cambio, Taskpodrían registrar una devolución de llamada para recibir los valores cuando estén listos.

En particular, el Taskqué no dicen qué es lo que se necesita mucho tiempo para devolver el valor. Se podría ser que se necesita mucho tiempo para calcular, o puede que se necesita mucho tiempo para buscarlo. Solo en el primer caso usarías a Threadpara ejecutar a Task. (En .NET, los subprocesos son extremadamente caros, por lo que generalmente desea evitarlos tanto como sea posible y realmente solo los usa si desea ejecutar múltiples cálculos pesados ​​en múltiples CPU. Por ejemplo, en Windows, un subproceso pesa 12 KiByte ( Creo que), en Linux, un hilo pesa tan solo 4 KiByte, en Erlang / BEAM incluso solo 400 Byte. ¡En .NET, es 1 MiByte!)

Jörg W Mittag
fuente
29
Curiosamente, en las primeras versiones preliminares de TPL (Task Parallel Library) había Task and Future <T>. El futuro <T> pasó a denominarse Tarea <T>. :)
Lee Campbell
23
¿Cómo calculó 1 MB para .NET?
dvallejo
55
@DanVallejo: Ese número fue mencionado en una entrevista con el equipo de diseño de TPL. No puedo decirte quién lo dijo o qué entrevista fue, lo vi hace años.
Jörg W Mittag
99
@RIPUNJAYTRIPATHI Claro, pero no necesita ser otro hilo, podría ser el hilo que solicitó el trabajo en primer lugar.
Chris Pitman
77
.NET solo usa subprocesos de Windows en Windows, por lo que el tamaño es el mismo, de manera predeterminada, generalmente 1 MiB de memoria virtual para ambos. La memoria física se usa según sea necesario en fragmentos del tamaño de una página (generalmente 64 kiB), lo mismo con el código nativo. El tamaño mínimo de la pila de subprocesos depende del sistema operativo: 256 kiB para Vista, por ejemplo. En x86 Linux, el valor predeterminado es generalmente 2 MiB, nuevamente, asignado en trozos del tamaño de una página. (simplificación) Erlang solo usa un subproceso del sistema por proceso, esos 400 bytes se refieren a algo similar a .NET Task.
Luaan
39

Hilo

Lo más básico, probablemente no necesite usarlo, probablemente pueda usar una LongRunningtarea y aprovechar los beneficios de TPL - Task Parallel Library, incluida en .NET Framework 4 (febrero de 2002) y superior (también .NET Núcleo).

Tareas

Abstracción sobre los hilos. Se utiliza el grupo de subprocesos (a menos que especifique la tarea como una LongRunningoperación, si es así, un nuevo hilo se crea bajo el capó para usted).

Grupo de hilos

Como su nombre indica: un grupo de hilos. ¿El framework .NET maneja un número limitado de hilos por usted? ¿Por qué? Porque abrir 100 hilos para ejecutar costosas operaciones de CPU en un procesador con solo 8 núcleos definitivamente no es una buena idea. El marco mantendrá este grupo para usted, reutilizando los hilos (sin crearlos / eliminándolos en cada operación) y ejecutando algunos de ellos en paralelo, de manera que su CPU no se queme.

OK, pero ¿cuándo usar cada uno?

En resumen: siempre use tareas.

La tarea es una abstracción, por lo que es mucho más fácil de usar. Le aconsejo que siempre intente usar tareas y si enfrenta algún problema que le obligue a manejar un hilo usted mismo (probablemente el 1% del tiempo), use hilos.

PERO ten en cuenta que:

  • I / O Bound : para operaciones vinculadas de E / S (llamadas a bases de datos, archivos de lectura / escritura, llamadas a API, etc.) evite usar tareas normales, use LongRunningtareas ( o subprocesos si es necesario ). Porque el uso de tareas lo llevaría a un grupo de subprocesos con algunos subprocesos ocupados y muchas otras tareas esperando su turno para tomar el grupo.
  • CPU Bound : para operaciones vinculadas a la CPU, solo use las tareas normales (que internamente usarán el grupo de subprocesos) y esté feliz.
fabriciorissetto
fuente
ligera corrección, un hilo no es una "cosa de metal desnudo". es implementado por el sistema operativo, la mayoría de las implementaciones transmiten características de la CPU y CS, pero el hardware no las implementa.
Tomer W
7

Puede usar Taskpara especificar lo que desea hacer y luego adjuntarlo Taskcon un Thread. para que Taskse ejecute en ese recién hecho en Threadlugar de en el hilo GUI.

Usar Taskcon el TaskFactory.StartNew(Action action). Aquí ejecuta un delegado, por lo que si no usó ningún hilo, se ejecutaría en el mismo hilo (hilo GUI). Si menciona un hilo, puede ejecutarlo Tasken un hilo diferente. Este es un trabajo innecesario porque puede ejecutar directamente el delegado o adjuntar ese delegado a un hilo y ejecutar ese delegado en ese hilo. Así que no lo uses. Es simplemente innecesario. Si tiene la intención de optimizar su software, este es un buen candidato para ser eliminado.

** Tenga en cuenta que el Actiones un delegate.

Gryphes
fuente
6

Además de los puntos anteriores, sería bueno saber que:

  1. Una tarea es por defecto una tarea en segundo plano. No puede tener una tarea en primer plano. Por otro lado, un subproceso puede ser de fondo o primer plano (use la propiedad IsBackground para cambiar el comportamiento).
  2. Las tareas creadas en el grupo de subprocesos reciclan los subprocesos, lo que ayuda a ahorrar recursos. Entonces, en la mayoría de los casos, las tareas deberían ser su opción predeterminada.
  3. Si las operaciones son rápidas, es mucho mejor usar una tarea en lugar de hilo. Para operaciones de larga duración, las tareas no ofrecen muchas ventajas sobre los hilos.
usuario2492339
fuente
4

Usualmente uso Taskpara interactuar con Winforms y un simple trabajador de fondo para que no congele la interfaz de usuario. Aquí un ejemplo cuando prefiero usarTask

private async void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    await Task.Run(() => {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
    })
    buttonDownload.Enabled = true;
}

VS

private void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    Thread t = new Thread(() =>
    {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
        this.Invoke((MethodInvoker)delegate()
        {
            buttonDownload.Enabled = true;
        });
    });
    t.IsBackground = true;
    t.Start();
}

la diferencia es que no necesitas usar un MethodInvokercódigo más corto.

ewwink
fuente
4

La tarea es como una operación que desea realizar, Thread ayuda a administrar esas operaciones a través de múltiples nodos de proceso. La tarea es una opción ligera, ya que Threading puede conducir a una gestión de código compleja
. Sugeriré que lea desde MSDN (Mejor en el mundo) siempre

Tarea

Hilo

Saurabh
fuente
3

Una tarea se puede ver como una manera conveniente y fácil de ejecutar algo de forma asincrónica y paralela.

Normalmente, una tarea es todo lo que necesita, no recuerdo si alguna vez he usado un hilo para algo más que la experimentación.

Puede lograr lo mismo con un hilo (con mucho esfuerzo) como puede hacerlo con una tarea.

Hilo

int result = 0;
Thread thread = new System.Threading.Thread(() => { 
    result = 1; 
});
thread.Start();
thread.Join();
Console.WriteLine(result); //is 1

Tarea

int result = await Task.Run(() => {
    return 1; 
});
Console.WriteLine(result); //is 1

Por defecto, una tarea utilizará Threadpool, lo que ahorra recursos, ya que crear subprocesos puede ser costoso. Puede ver una Tarea como una abstracción de nivel superior en subprocesos.

Como señala este artículo , la tarea proporciona las siguientes características potentes a través de hilo.

  • Las tareas están ajustadas para aprovechar los procesadores multinúcleo.

  • Si el sistema tiene varias tareas, utiliza internamente el grupo de subprocesos CLR y, por lo tanto, no tiene la sobrecarga asociada con la creación de un subproceso dedicado mediante el subproceso. También reduzca el tiempo de cambio de contexto entre múltiples hilos.

  • La tarea puede devolver un resultado. No existe un mecanismo directo para devolver el resultado del hilo.
  • Espere en un conjunto de tareas, sin una construcción de señalización.

  • Podemos encadenar tareas para ejecutar una tras otra.

  • Establezca una relación padre / hijo cuando una tarea se inicia desde otra tarea.

  • La excepción de tarea secundaria puede propagarse a la tarea principal.

  • Cancelación de soporte de tareas mediante el uso de tokens de cancelación.

  • La implementación asincrónica es fácil en la tarea, utilizando palabras clave 'async' y 'wait'.

CharithJ
fuente