Programas que afirman que no son "multi-core" amigables

17

Usted ve esta frase o similar de vez en cuando, generalmente refiriéndose a un programa que afirma que no fueron diseñados para aprovechar al máximo los procesadores multi-core. Esto es común especialmente con la programación de videojuegos. (por supuesto, muchos programas no tienen concurrencia y no la necesitan, como scripts básicos, etc.).

¿Cómo puede ser esto? Muchos programas (especialmente juegos) utilizan la concurrencia de forma inherente, y dado que el sistema operativo se encarga de la programación de tareas en la CPU, ¿estos programas no aprovechan inherentemente los múltiples núcleos disponibles? ¿Qué significaría en este contexto "aprovechar múltiples núcleos"? ¿Están estos desarrolladores realmente prohibiendo la programación de tareas del sistema operativo y forzando la afinidad o su propia programación? (Suena como un problema importante de estabilidad).

Soy un programador de Java, así que tal vez no he tenido que lidiar con esto debido a abstracciones o cosas por el estilo.

SnakeDoc
fuente
11
Una gran posibilidad es que se tomaron atajos en la sincronización, que funcionan para un sistema de procesador único / núcleo pero rompen con la verdadera concurrencia de múltiples procesadores / núcleos.
Bart van Ingen Schenau
@BartvanIngenSchenau: Esto es correcto. Debería expandir esto y publicarlo como respuesta. Creo que todos los demás perdieron el punto.
Kevin Cline
1
Creo que @Bart está muy cerca. Sin embargo, s / work / parece funcionar / y estará más cerca de la marca.
Ben Voigt
aparte: he tenido experiencia con esto como usuario en lugar de programador: Ground Control 2 en Windows XP. Necesitaba establecer la afinidad central a un solo núcleo en un sistema multinúcleo para que se ejecute correctamente, de lo contrario, todas las animaciones (de hecho, todo el juego) se ejecutarían a una velocidad de 10x, lo que, aunque era un desafío, se volvió un poco molesto después de un tiempo . No he hecho ningún trabajo en los juegos, pero en mi opinión, una parte del juego parecía depender de que el procesador solo realizara una cierta cantidad de trabajo al mismo tiempo.
jammypeach

Respuestas:

28

La buena concurrencia requiere mucho más que lanzar algunos hilos en una aplicación y esperar lo mejor. Hay un rango en la concurrencia de un programa de vergonzosamente paralelo a secuencial pura. Cualquier programa puede usar la ley de Amdahl para expresar cuán escalable es un problema o algoritmo. Un par de calificaciones para una aplicación vergonzosamente paralela sería:

  • Sin estado compartido, cada función solo depende de los parámetros pasados
  • Sin acceso a dispositivos físicos (tarjetas gráficas, discos duros, etc.)

Hay otras calificaciones, pero con solo estas dos podemos entender por qué los juegos en particular no son tan fáciles como podría pensarse para aprovechar múltiples núcleos. Por un lado, el modelo del mundo que se representará debe compartirse ya que las diferentes funciones calculan la física, el movimiento, aplican inteligencia artificial, etc. Segundo, cada cuadro de este modelo de juego debe representarse en la pantalla con una tarjeta gráfica.

Para ser justos, muchos creadores de juegos usan motores de juegos producidos por terceros. Tomó un tiempo, pero estos motores de juegos de terceros ahora son mucho más paralelos de lo que solían ser.

Hay desafíos arquitectónicos más grandes al tratar con la concurrencia efectiva

La concurrencia puede tomar muchas formas, desde ejecutar tareas en segundo plano hasta un soporte arquitectónico completo para la concurrencia. Algunos idiomas le brindan características de concurrencia muy potentes, como ERLANG , pero requiere que piense de manera muy diferente sobre cómo construir su aplicación.

No todos los programas realmente necesitan la complejidad del soporte multinúcleo completo. Un ejemplo de esto es el software de impuestos, o cualquier aplicación basada en formularios. Cuando pasa la mayor parte de su tiempo esperando que el usuario haga algo, la complejidad de las aplicaciones multiproceso simplemente no es tan útil.

Algunas aplicaciones se prestan a una solución paralela más vergonzosa, como las aplicaciones web. En este caso, la plataforma comienza vergonzosamente paralela y depende de usted no tener que imponer contención de hilos.

La línea de fondo:

No todas las aplicaciones se ven realmente perjudicadas por no aprovechar múltiples hilos (y por lo tanto, núcleos). Para los que están afectados por eso, a veces los cálculos no son amigables con el procesamiento paralelo o la sobrecarga para coordinarlo haría que la aplicación sea más frágil. Desafortunadamente, el procesamiento paralelo todavía no es tan fácil como debería ser hacerlo bien.

Berin Loritsch
fuente
Este es un gran análisis. Sin embargo, una cosa que me molesta es su punto sobre que los programas del mundo real a menudo no son vergonzosamente paralelos y, por lo tanto, difíciles de paralelizar: si bien puede ser imposible hacer lo mismo en paralelo, puede ser muy fácil hacer cosas diferentes en paralelo ( por ejemplo, en una arquitectura de canalización o con un subproceso de interfaz de usuario separado).
amon
8
El punto real es que necesita diseñar para una ejecución paralela, y si no lo hace, está limitado por su falta de diseño. Estoy de acuerdo en que puede ser muy fácil hacer cosas diferentes en paralelo, pero no si es una aplicación existente con altas expectativas de los usuarios. En ese caso, es muy posible que necesite una reescritura para hacerlo posible. Las reescrituras son inherentemente arriesgadas, pero ocasionalmente puedes hacer un buen argumento para ellas. He hecho un par de reescrituras que maximizan el procesamiento paralelo al tiempo que conservan la mayor cantidad de código posible. Hay muchos factores ocultos.
Berin Loritsch
Gran respuesta. Vale la pena enfatizar que no solo puede haber rendimientos decrecientes al paralelizar algunos sistemas, sino que algunos de hecho pueden ser más lentos debido a la sobrecarga necesaria para hacerlos paralelos. En particular, muchos semáforos / bloqueos y cambios de contexto pueden tener efectos adversos en el tiempo de ejecución. El cambio de contexto en particular podría reducir la efectividad de la memoria caché, lo cual es una preocupación no trivial si está a punto de optimizar su sistema. El ejemplo de OP de motores de juegos en particular me lleva a recordar haber escuchado mucho más sobre la optimización del almacenamiento en caché que el acceso paralelo.
Gankro
35

Muchos programas (especialmente juegos) utilizan de forma inherente la concurrencia,

No, en realidad es lo contrario. La mayoría de las aplicaciones están escritas en una mentalidad de subproceso único, y los desarrolladores nunca realizaron los cambios necesarios para admitir la concurrencia.

En C, C ++ y C #, debe indicar explícitamente a la aplicación que inicie nuevos subprocesos y / o procesos.

Creo que te estás enfocando demasiado en la programación de los hilos y no lo suficiente en el manejo de datos dentro de los hilos potenciales. Compartir datos a través de hilos y / o procesos requiere alguna forma de sincronización. Si cambia una aplicación para usar varios subprocesos pero no logra establecer esa sincronización, es probable que vea muchos errores difíciles de rastrear en el código.

Para las aplicaciones multiproceso en las que he trabajado, generalmente nunca me he preocupado por el envío y solo por la sincronización de datos. Las únicas veces que tuve que preocuparme por el envío fue cuando estaba persiguiendo condiciones de carrera debido a una sincronización de datos incorrecta.

En general, cuando una aplicación dice que no puede usar múltiples núcleos, significa que no tienen la sincronización para proteger la manipulación de datos.


fuente
¿Esto es cierto incluso para los nuevos programas modernos de grandes desarrolladores / editores? Cuando me siento y escribo un programa, una de las primeras cosas en la etapa de diseño que pienso es: ¿necesito concurrencia? Porque puede dar como resultado un diseño drásticamente diferente. Los juegos en particular deben tener cierto nivel de concurrencia, de lo contrario, el juego se congelaría cuando uno de los miles de modelos en pantalla intentara hacer algo ...
SnakeDoc
55
@SnakeDoc: creo que estás confundiendo tus dominios allí. Las compañías de Big Game ciertamente escriben teniendo en cuenta la concurrencia, pero aún no he visto un juego de Big Game que no sea compatible con la concurrencia. Las aplicaciones y juegos que he visto que no pueden admitir concurrencia generalmente son de tiendas más pequeñas / desarrolladores individuales donde no habrían comenzado con esa mentalidad. Y en algún momento de la evolución de la aplicación, es imposible atornillar la concurrencia después del hecho. Y algunas aplicaciones nunca tuvieron la intención de hacer lo suficiente para justificar la concurrencia.
Y también algunos juegos prosperan con nuevo contenido (gráficos y jugabilidad), sin tener que actualizar el motor del juego (implementación del código). Por lo tanto, el motor del juego podría estar atrasado en tecnología.
rwong
66
@SnakeDoc: No necesita concurrencia para lidiar con miles de modelos en pantalla. No es que cada objeto en tu juego necesite su propio hilo para simularlo; un hilo puede manejar las actualizaciones de todo en la pantalla en cada paso de tiempo.
user2357112 es compatible con Monica
13

Esto no se trata tanto de múltiples núcleos como de múltiples hilos. El sistema operativo puede programar un subproceso para que se ejecute en el núcleo que desee, y esta programación es transparente para el programa que se está programando. Sin embargo, muchos programas no se escriben utilizando múltiples hilos, por lo que solo pueden ejecutarse en un núcleo a la vez.

¿Por qué escribiría un programa de subproceso único? Son más fáciles de escribir y de depurar: una cosa sucede después de otra (en lugar de que sucedan varias cosas a la vez y es posible que se interpongan entre sí). O su programa puede no estar dirigido a máquinas de múltiples núcleos (como fue el caso con los juegos antiguos). En algunos casos, un programa de subprocesos múltiples podría incluso ejecutarse más lentamente que una versión de subprocesos simples si la sobrecarga de los conmutadores de contexto y la comunicación entre subprocesos supera la velocidad obtenida por la ejecución paralela (algunas partes del programa pueden no ser paralelizables).

amon
fuente
8

Esta no es una respuesta completa. Es una historia de advertencia.

Un día pensé que les mostraría a los estudiantes en mi curso de programación concurrente una clasificación rápida paralela. Quicksort debería paralelizarse bien, pensé. Usé dos hilos. Lo ejecuté en mi computadora de un solo núcleo. Los resultados fueron:

  • 14 segundos para una versión de subproceso único.
  • 15 segundos para la versión de 2 hilos.

Esto fue sobre lo que esperaba.

Luego lo probé en una nueva máquina de doble núcleo.

  • 11 segundos para la versión de subproceso único.
  • 20 segundos para la versión de 2 hilos.

Los dos hilos compartieron una cola de tareas restantes. Parece que los campos del objeto de la cola se barajan de un lado a otro entre el caché de un núcleo y el del otro.

Theodore Norvell
fuente
2
¿Con cuántos elementos de matriz probaste? ¿Quizás mergesort sería más adecuado ya que la programación multinúcleo habría requerido la copia de datos para evitar conflictos de línea de caché?
rwong
2
@rwong Había 10,000,000 elementos de matriz. Ciertamente, mergesort se paralelizaría bien. Si hubiera utilizado la combinación, probablemente no habría aprendido una lección útil.
Theodore Norvell
1
@ArlaudPierre Consideraré paralelizar cualquier algoritmo. Quicksort es interesante ya que puede utilizar el enfoque de la bolsa de tareas para ello. Como las tareas son independientes, mi intuición era que debería ser un ejemplo de paralelismo embarazoso. Debo mencionar que, después de un poco de ajuste, en realidad tuvo una aceleración cercana a 2.
Theodore Norvell
1
@Jules La respuesta es el equilibrio de carga. También quería escribirlo de manera que el número de hilos sea fácil de cambiar. Su enfoque generaliza muy bien a potencias de 2, pero no tan bien a otros números de hilos.
Theodore Norvell
2
@MaciejPiechotka La moral es prácticamente todo lo que sugieres. Pero volviendo al OP, creo que la moraleja más relevante es que los programas multiproceso pueden ejecutarse (mucho) más lentamente en una arquitectura de múltiples núcleos que en un procesador de un solo núcleo, a menos que se haya hecho un esfuerzo para garantizar lo contrario.
Theodore Norvell