Red de conocimiento informático - Material del sitio web - Cómo utilizar Python para lograr simultaneidad de alto rendimiento, computación GPU y aprendizaje profundo

Cómo utilizar Python para lograr simultaneidad de alto rendimiento, computación GPU y aprendizaje profundo

El primero es la sobrecarga de la concurrencia en sí misma: la sobrecarga de abrir nuevos subprocesos de procesamiento, cerrar subprocesos de procesamiento y rotar intervalos de tiempo entre múltiples subprocesos de procesamiento.

De hecho, para escenarios de aplicaciones menos complejos, estos gastos generales son incluso mayores que los gastos generales que supone procesar realmente la parte lógica del código. Por lo tanto, decidimos utilizar un método de concurrencia basado en concurrencia, es decir, solo hay un proceso de servicio (una sola CPU), el proceso de servicio mantiene internamente todos los datos de la solicitud y el proceso de servicio programa la secuencia de procesamiento de diferentes solicitudes por En sí mismo, evita el método tradicional de concurrencia de subprocesos múltiples. La sobrecarga de crear, destruir y programar subprocesos de procesamiento. Con base en esta consideración, optamos por implementar el desarrollo de servicios API basados ​​​​en el marco Tornado. La implementación de tornado es muy simple y clara: utiliza generadores de Python para concurrencia e IOLoop para implementar colas de programación.

El segundo problema es el rendimiento de la base de datos. Las bases de datos mencionadas aquí incluyen MongoDB y Redis, que presentaré por separado aquí.

Primero, analizaremos MongoDB, que almacena principalmente diferentes configuraciones de autenticación para diferentes usuarios, como qué tipo de imágenes deben mostrarse.

Inicialmente, cada solicitud de autenticación consulta MongoDB. En ese momento, nuestro MongoDB estaba puramente en memoria y tres máquinas formaban un conjunto de réplicas al mismo tiempo. Esta combinación podía cargar de manera estable alrededor de 8000 o 9000 qps. Más tarde, a medida que nuestro volumen de autenticación aumentó, la capacidad de carga se convirtió gradualmente en nuestro cuello de botella. .

Para resolver completamente este problema, propusimos la solución más extrema, que es almacenar en caché directamente los datos de la base de datos en el proceso de servicio para actualizaciones periódicas por lotes, de modo que la sobrecarga de consultas se reduzca considerablemente. . Pero debido a que usamos Python y debido a la existencia de GIL, se bifurcarán 8 procesos de servicio en un servidor de 8 núcleos. Los procesos no son tan convenientes como los subprocesos, por lo que escribimos un conjunto de algoritmos asociados basados ​​​​en mmap y construimos una cruz. -proceso **** Disfrute del almacenamiento en caché. Desde que este caché se puso en línea, la carga en Mongodb ha sido casi nula.

Después de hablar de MongoDB, hablemos de Redis. Redis tiene un código simple, estructuras de datos ricas y un rendimiento potente, pero el único problema es que, como programa de un solo proceso, su rendimiento tiene un límite superior.

Aunque Redis lanzó una versión oficial del clúster este año, después de las pruebas, creemos que el tiempo de recuperación de fallas de este programa distribuido no es ideal y el costo de operación y mantenimiento es alto. Antes de que saliera el programa de clúster oficial de Redis, ya existían muchos programas proxy en el mundo del código abierto, como TwemProxy de Twitter y Codis de PeaPod. Después de probar estos dos programas, sentimos que la operación y el mantenimiento de TwemProxy todavía son relativamente problemáticos, mientras que Codis es muy fácil de usar, ya sea modificando la configuración o expandiéndola, se puede completar en la página de configuración y el rendimiento. es relativamente bueno.

Después de casi probar varias soluciones, todavía estamos decididos a implementar una solución distribuida. El propósito es que sea altamente adecuada para nuestras necesidades, y el costo de operación y mantenimiento debe ser bajo, fácil de expandir y de conmutación por error rápida. y, finalmente, lo importante es que debe existir redundancia de datos.

Con base en las consideraciones anteriores, determinamos una solución distribuida basada en el cliente y utilizamos zookeeper para sincronizar el estado y garantizar una alta disponibilidad. Específicamente, modificamos el código fuente de Redis para registrarlo en zookeeper. El cliente obtiene la información en el clúster del servidor Redis a través de zookeeper y calcula en qué Redis deben almacenarse los datos según el algoritmo hash consistente unificado y escribe una copia. los datos redundantes en el siguiente anillo hash de Redis. Cuando falla la lectura de los datos originales, puede intentar leer inmediatamente los datos redundantes sin interrumpir el servicio.