¿Cuánto sobrecarga hay al crear un hilo?


Acabo de revisar un código realmente terrible: código que envía mensajes en un puerto serie creando un nuevo hilo para empaquetar y ensamblar el mensaje en un nuevo hilo para cada mensaje enviado. Sí, para cada mensaje se crea un pthread, los bits se configuran correctamente, luego el hilo termina. No tengo ni idea de por qué alguien haría tal cosa, pero plantea la pregunta: ¿cuánta sobrecarga hay cuando realmente se crea un hilo?

Author: jdt141, 2010-10-14

9 answers

...envía mensajes en un puerto serie ... para cada mensaje se crea un pthread, los bits se configuran correctamente, luego el hilo termina. ...¿cuánta sobrecarga hay cuando realmente se crea un hilo?

Esto es altamente específico del sistema. Por ejemplo, la última vez que usé el subproceso de máquinas virtuales fue una pesadilla lenta (han pasado años, pero desde la memoria un subproceso podría crear algo así como 10 más por segundo (y si lo mantuvieras durante unos segundos sin subprocesos saliendo del núcleo)), mientras que en Linux probablemente puede crear miles. Si quieres saber exactamente, compararlo en su sistema. Pero, no es de mucho uso saber que sin saber más sobre los mensajes: si promedian 5 bytes o 100k, si se envían de forma contigua o los idles de línea en el medio, y cuáles son los requisitos de latencia para la aplicación son tan relevantes para la idoneidad del uso del subproceso del código como cualquier medida absoluta de la sobrecarga de creación de subprocesos. Y el rendimiento puede no haber necesitado ser la consideración dominante del diseño.

 6
Author: Tony Delroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-14 04:58:16

Para resucitar este viejo hilo, acabo de hacer un simple código de prueba:

#include <thread>

int main(int argc, char** argv)
{
  for (volatile int i = 0; i < 500000; i++)
    std::thread([](){}).detach();
  return 0;
}

Lo compilé con g++ test.cpp -std=c++11 -lpthread -O3 -o test. Luego lo ejecuté tres veces seguidas en un viejo (kernel 2.6.18) muy cargado (haciendo una reconstrucción de la base de datos) portátil lento (Intel core i5-2540M). Resultados de tres corridas consecutivas: 5.647 s, 5.515 s y 5.561 s. Así que estamos viendo un poco más de 10 microsegundos por hilo en esta máquina, probablemente mucho menos en la suya.

Eso no es mucha sobrecarga en absoluto, dado que los puertos serie maximizan alrededor de 1 bit por 10 microsegundos. Ahora, por supuesto, hay varias pérdidas de subprocesos adicionales que se pueden obtener involucrando argumentos pasados / capturados (aunque las llamadas a funciones pueden imponer algunos), ralentizaciones de caché entre núcleos (si varios subprocesos en diferentes núcleos están luchando sobre la misma memoria al mismo tiempo), etc. Pero, en general, dudo mucho que el caso de uso que presentó tenga un impacto adverso en el rendimiento (y podría proporcionar beneficios, dependiendo), a pesar de tener ya etiquetó preventivamente el concepto de "código realmente terrible" sin siquiera saber cuánto tiempo lleva lanzar un hilo.

Si es una buena idea o no depende mucho de los detalles de su situación. ¿De qué más es responsable el hilo de llamada? ¿Qué es exactamente lo que está involucrado en la preparación y escritura de los paquetes? ¿Con qué frecuencia se escriben (con qué tipo de distribución? uniforme, agrupado, etc...?) y ¿cómo es su estructura? Cuántos núcleos tiene el sistema? Sucesivamente. Dependiendo de los detalles, la solución óptima podría estar en cualquier lugar de "sin hilos en absoluto" a "grupo de hilos compartidos" a "hilo para cada paquete".

Tenga en cuenta que los grupos de subprocesos no son mágicos y en algunos casos pueden ser una desaceleración frente a subprocesos únicos, ya que una de las mayores ralentizaciones con subprocesos es la sincronización de la memoria caché utilizada por varios subprocesos al mismo tiempo, y los grupos de subprocesos por su propia naturaleza de tener que buscar y procesar actualizaciones de un subproceso diferente tienen que hacer esto. Por lo tanto, su subproceso primario o subproceso de procesamiento hijo puede quedarse atascado teniendo que esperar si el procesador no está seguro de si el otro proceso ha alterado una sección de memoria. Por el contrario, en una situación ideal, un subproceso de procesamiento único para una tarea dada solo tiene que compartir memoria con su tarea de llamada una vez (cuando se inicia) y luego nunca interfieren entre sí de nuevo.

 29
Author: Nafnlaus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-04 11:01:43

Definitivamente no quieres hacer esto. Cree un solo hilo o un grupo de hilos y solo señale cuando los mensajes estén disponibles. Al recibir la señal, el hilo puede realizar cualquier procesamiento de mensajes necesario.

En términos de sobrecarga, la creación/destrucción de subprocesos, especialmente en Windows, es bastante costosa. En algún lugar del orden de decenas de microsegundos, para ser específicos. En su mayor parte, solo debe hacerse al inicio / final de una aplicación, con la posible excepción de grupos de subprocesos dinámicamente redimensionados.

 10
Author: Michael Goldshteyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-14 03:13:40

Siempre me han dicho que la creación de hilos es barata, especialmente cuando se compara con la alternativa de crear un proceso. Si el programa del que estás hablando no tiene muchas operaciones que necesitan ejecutarse simultáneamente, entonces el enhebrado podría no ser necesario, y a juzgar por lo que escribiste, este podría ser el caso. Algo de literatura para apoyarme:

Http://www.personal.kent.edu / ~rmuhamma/OpSystems/Myos/threads.htm

Los hilos son baratos en el sentido que

  1. Solo necesitan una pila y almacenamiento para registros por lo tanto, los hilos son baratos de crear.

  2. Los hilos utilizan muy pocos recursos de un sistema operativo en que están trabajando. Eso es, los hilos no necesitan nuevo espacio de direcciones, datos globales, código de programa u operación recursos del sistema.

  3. El cambio de contexto es rápido cuando se trabaja con subprocesos. La razón es que solo tenemos que salvar y / o restaurar PC, SP y registros.

Más de lo mismo aquí.

En Operating System Concepts 8th Edition (página 155) los autores escriben sobre los beneficios de threading:

La asignación de memoria y recursos para la creación de procesos es costosa. Porque temas compartir el recurso de la proceso al que pertenecen, es más económico para crear y hilos de cambio de contexto. Empíricamente medir la diferencia en los gastos generales puede ser difícil, pero en general es mucho más tiempo para crear y administrar procesos que subprocesos. En Solaris, por ejemplo, creando un el proceso es aproximadamente treinta veces más lento que es crear un hilo, y el contexto el cambio es cinco veces más lento.

 9
Author: ubiquibacon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-14 04:37:22

Hay algo de sobrecarga en la creación de subprocesos, pero comparándolo con las tasas de baudios generalmente lentas del puerto serie (19200 bits/seg es el más común), simplemente no importa.

 7
Author: ruslik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-14 03:11:57

Para comparar , echa un vistazo a OSX: Link

  • Estructuras de datos del núcleo: Aproximadamente 1 KB Espacio de pila: 512 KB (subprocesos secundarios): 8 MB (subproceso principal de OS X), 1 MB (subproceso principal de iOS thread)

  • Tiempo de creación: Aproximadamente 90 microsegundos

La creación del hilo posix también debería estar alrededor de esto (no una cifra muy lejana), supongo.

 3
Author: Lunar Mushrooms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-28 04:43:25

La creación de subprocesos y la computación en un subproceso son bastante caras. Todas las estructuras de datos necesitan ser configuradas, el subproceso registrado con el kernel y un interruptor de subproceso debe ocurrir para que el nuevo subproceso realmente se ejecute (en un tiempo no especificado e impredecible). Ejecución del hilo.start no significa que la función principal del hilo se llame inmediatamente. Como el artículo (mencionado por typoking) señala la creación de un hilo es barato solo en comparación con la creación de un proceso. En general, es bastante caro.

Nunca usaría un hilo

  • para un cálculo corto
  • un cálculo donde necesito el resultado en mi flujo de código (que significa que estoy empezando el hilo y esperar a que devuelva el resultado de es la computación

En tu ejemplo, tendría sentido (como ya se ha señalado) crear un hilo que maneje toda la comunicación en serie y sea eterno.

Hth

Mario

 2
Author: Mario The Spoon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-14 04:47:44

En cualquier implementación sana, el costo de la creación de subprocesos debe ser proporcional al número de llamadas al sistema que implica, y en el mismo orden de magnitud que las llamadas al sistema familiares como open y read. Algunas mediciones casuales en mi sistema mostraron que pthread_create toma aproximadamente el doble de tiempo que open("/dev/null", O_RDWR), lo que es muy caro en relación con la computación pura, pero muy barato en relación con cualquier IO u otras operaciones que implicarían cambiar entre el usuario y el espacio del núcleo.

 2
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-24 16:47:17

Usé el diseño "terrible" anterior en una aplicación VOIP que hice. Funcionó muy bien ... absolutamente ninguna latencia o paquetes perdidos/perdidos para equipos conectados localmente. Cada vez que llegaba un paquete de datos, se creaba un subproceso y se entregaban esos datos para procesarlos a los dispositivos de salida. Por supuesto, los paquetes eran grandes, por lo que no causaban cuellos de botella. Mientras tanto, el hilo principal podría volver a esperar y recibir otro paquete entrante.

He probado otros diseños donde los hilos I necesidad se crean de antemano, pero esto crea sus propios problemas. Primero debe diseñar su código correctamente para que los subprocesos recuperen los paquetes entrantes y los procesen de manera determinista. Si utiliza múltiples hilos (pre-asignados) es posible que los paquetes puedan ser procesados 'fuera de orden'. Si utiliza un único subproceso (preasignado) para realizar un bucle y recoger los paquetes entrantes, existe la posibilidad de que el subproceso encuentre un problema y termine sin dejar subprocesos para procesar ninguno datos.

Crear un subproceso para procesar cada paquete de datos entrante funciona de manera muy limpia, especialmente en sistemas multinúcleo y donde los paquetes entrantes son grandes. También para responder a su pregunta más directamente, la alternativa a la creación de subprocesos es crear un proceso en tiempo de ejecución que administre los subprocesos preasignados. Ser capaz de sincronizar la transferencia y el procesamiento de datos, así como detectar errores, puede agregar tanto, si no más sobrecarga, como simplemente crear un nuevo hilo. Todo depende de su diseño y requisitos.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-07 20:59:56