2010-05-08 8 views
9

Imagine que tengo dos (tres, cuatro, lo que sea) tareas que tienen que ejecutarse en paralelo. Ahora, la manera más fácil de hacer esto sería crear hilos separados y olvidarse de eso. Pero en una vieja y simple CPU de un solo núcleo eso significaría una gran cantidad de cambio de contexto, y todos sabemos que el cambio de contexto es grande, malo, lento y, en general, simplemente Evil. Debe evitarse, ¿verdad?¿Qué tan caro es un cambio de contexto? ¿Es mejor implementar un cambio de tarea manual que confiar en los hilos del sistema operativo?

En ese sentido, si estoy escribiendo el software desde cero todos modos, podría ir más allá y poner en práctica mi propia tarea de conmutación. Divida cada tarea en partes, guarde el estado entre ellas, y luego cambie entre ellas dentro de un solo hilo. O bien, si detecto que hay múltiples núcleos de CPU, podría asignar cada tarea a un hilo por separado y todo estaría bien.

La segunda solución tiene la ventaja de adaptarse al número de núcleos de CPU disponibles, pero va a la tarea-interruptor manual realmente ser más rápido que el que está en el núcleo del sistema operativo? Especialmente si estoy tratando de hacer todo genérico con un TaskManager y un ITask, etc.

Aclaración: Soy un desarrollador de Windows, por lo que estoy interesado principalmente en la respuesta para este sistema operativo, pero sería muy interesante conocer otros sistemas operativos también. Cuando escriba su respuesta, indique para qué sistema operativo es.

Más aclaración: Bien, entonces esto no está en el contexto de una aplicación en particular. En realidad es una pregunta general, el resultado de mis reflexiones sobre la escalabilidad. Si quiero que mi aplicación escale y utilice de manera efectiva las futuras CPU (e incluso las diferentes CPU de hoy en día), debo hacerlo con subprocesos múltiples. Pero, ¿cuántos hilos? Si hago un número constante de subprocesos, entonces el programa funcionará de manera subóptima en todas las CPU que no tengan la misma cantidad de núcleos.

Lo ideal sería que el número de hilos sería determinado en tiempo de ejecución, pero pocas son las tareas que realmente se pueden dividir en el número arbitrario de piezas en tiempo de ejecución. Sin embargo, muchas tareas se pueden dividir en una cantidad bastante grande y constante de hilos en el momento del diseño. Entonces, por ejemplo, si mi programa pudiera engendrar 32 hilos, ya utilizaría todos los núcleos de hasta 32 núcleos de CPU, lo cual está bastante lejos en el futuro (creo). Pero en una CPU simple de un solo núcleo o doble núcleo significaría MUCHO cambio de contexto, lo que ralentizaría las cosas.

Por lo tanto, mi idea sobre la conmutación manual de tareas. De esta forma, uno podría hacer 32 hilos "virtuales" que se mapearían con tantos hilos reales como sea óptimo, y el "cambio de contexto" se haría manualmente. La pregunta es: ¿la sobrecarga de mi manual "cambio de contexto" sería menor que la del cambio de contexto del sistema operativo?

Naturalmente, todo esto se aplica a los procesos que están vinculados a la CPU, como los juegos. Para su aplicación CRUD corriente, esto tiene poco valor. Tal aplicación se hace mejor con un hilo (como máximo dos).

+0

¿Qué sistema operativo le interesa? Esto varía * ampliamente * en todos los sistemas operativos. –

+1

Básicamente soy un programador de Windows, pero sería interesante conocer otros sistemas operativos también. Traté de hacer la pregunta bastante agnóstica para el sistema operativo. –

+0

@Vilx Esta pregunta, por su propia naturaleza, nunca puede ser ajena al sistema operativo. – Cromulent

Respuesta

5

No veo cómo un cambio de tarea manual podría ser más rápido ya que el kernel del sistema operativo todavía está cambiando otros procesos, incluido el suyo fuera del estado de ejecución. Parece una optimización prematura y una enorme pérdida de esfuerzo.

Si el sistema no está haciendo nada más, es probable que no tenga una gran cantidad de conmutadores de contexto de todos modos. El hilo usará su ciclo de tiempo, el programador del kernel verá que nada más necesita ejecutarse y volverá directamente a su hilo. Además, el sistema operativo hará un gran esfuerzo para evitar el movimiento de subprocesos entre las CPU, por lo que se beneficiará con el almacenamiento en caché.

Si realmente está vinculado a la CPU, detecte la cantidad de CPU y comience con esa cantidad de subprocesos. Debería ver casi el 100% de utilización de la CPU. Si no es así, no está completamente vinculado a la CPU y quizás la respuesta sea iniciar subprocesos N + X. Para procesos muy vinculados a IO, estaría comenzando un múltiplo (grande) del recuento de CPU (es decir, servidores web de alto tráfico que ejecutan más de 1000 subprocesos).

Finalmente, como referencia, los programadores de Windows y Linux se activan cada milisegundo para verificar si se debe ejecutar otro proceso. Entonces, incluso en un sistema inactivo, verá más de 1000 conmutadores de contexto por segundo. En sistemas muy cargados, he visto más de 10.000 por segundo por CPU sin ningún problema significativo.

+0

En otras palabras, incluso si hiciera como 32 subprocesos vinculados a la CPU en un sistema de un solo núcleo, la desaceleración en comparación con una solución de subproceso sería insignificante. –

+0

No creo que la sobrecarga sea despreciable, solo quería decir que una CPU puede manejar una gran cantidad de conmutadores de contexto y aún así hacer el trabajo. Debería ejecutar algunas pruebas para determinar la sobrecarga y si está de acuerdo con ello. Depende de cuánto tiempo se ejecuta este proceso: 1 ms de sobrecarga para una tarea que lleva 10 segundos, probablemente no importe; tal vez 1 segundo de sobrecarga lo haría.Es bastante fácil obtener la cantidad de CPU en un sistema; usted ya tiene un algoritmo que es fácil de diferenciar, por lo que _cualquier sobrecarga puede no ser aceptable y debe ejecutar un único enrutador en un sistema único. – AngerClown

3

unipolares máquinas Windows van a extinguirse en los próximos años, así que por lo general escribir nuevo código con el supuesto de que varios núcleos es el caso común. Yo diría que vaya con la administración de subprocesos del sistema operativo, que se encargará automáticamente de la concurrencia que proporcione el hardware, ahora y en el futuro.

No sé lo que hace su aplicación, pero a menos que tenga múltiples tareas en términos de computación, dudo que los cambios de contexto son un importante cuello de botella en la mayoría de las aplicaciones. Si sus tareas se bloquean en E/S, entonces no obtendrá muchos beneficios si intenta superar el sistema operativo.

+0

Naturalmente, esto se aplica solo a los procesos vinculados a la CPU. No quise decir nada más. Pero incluso cuando tiene un proceso vinculado a la CPU y está buscando una CPU multinúcleo, ¿cómo escribe su proceso para garantizar la utilización óptima de todos los núcleos disponibles, ya sea que haya 2 o 32? –

+0

OpenMP hace que sea bastante fácil escalar automáticamente las cosas a la cantidad de núcleos. La API de Windows proporciona grupos de subprocesos, que se supone que crecen y disminuyen automáticamente según la disponibilidad y el uso del procesador. O vea http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine si desea saber la cantidad de núcleos. –

5

La única ventaja de interruptor manual que puedo ver es que usted tiene un mejor control de dónde y cuando el interruptor pasa.El lugar ideal es, por supuesto, después de se ha completado una unidad de trabajo para que pueda destrozar todo junto. Esto le ahorra un error de caché.

Aconsejo no gastar su esfuerzo en esto.

Cuestiones relacionadas