Por qué cambié de Python a Go
Para ser honesto, es bastante estresante explicar frente a un grupo de usuarios de Python por qué abandonaron Python y cambiaron. La batalla de idiomas es como la batalla entre vim y emacs. p> p>
Un tema eterno sin respuesta, un pequeño descuido puede provocar fuertes contraataques por parte de los aficionados. Así que solo comenzaré con la situación real de nuestro proyecto y hablaré de por qué finalmente elegí ir.
Por qué abandonamos Python
En primer lugar, tengo que hablar sobre por qué elegimos Python. Antes de unirme al equipo de disco rápido empresarial, todo el proyecto, incluido el disco rápido Kingsoft anterior, se desarrolló utilizando Python. En cuanto a por qué elegí este método, el arquitecto Congtou en ese momento me dijo que era principalmente porque Python era fácil de iniciar y desarrollarse rápidamente. Para la mayoría de los estudiantes del equipo que no tienen experiencia en el desarrollo del lado del servidor, Python es realmente una buena opción.
Soy profundamente consciente de la simplicidad y eficiencia de Python. En ese momento, el proyecto de nube privada solo tenía unos pocos programadores, pero teníamos que atender a muchas empresas grandes y realizar un desarrollo personalizado. Gracias a Python, pudimos comenzar rápidamente. Más tarde, después de que fallara el disco Enterprise Express, comenzamos el proyecto de Office ligero y, naturalmente, usamos Python para construir la versión original.
Aunque Python es muy poderoso, también encontramos algunos problemas al usarlo, principalmente por los siguientes aspectos:
Lenguaje dinámico
Python es un lenguaje escrito dinámicamente. idioma. Sin embargo, aún pueden ocurrir errores de tiempo de ejecución como int + string, porque para una variable, al escribir código, a veces olvidamos fácilmente de qué tipo es la variable.
En Python, se puede permitir que aparezcan funciones con el mismo nombre. La última función sobrescribirá la anterior. Una vez, esto causó un error grave en nuestro sistema.
Como se mencionó anteriormente, el lenguaje estático puede ayudarnos a detectarlo al compilar, sin tener que esperar hasta el tiempo de ejecución para descubrir problemas. Aunque tenemos casos de prueba muy completos, siempre hay casos que se pasan por alto. Entonces, cada vez que ocurre un error de tiempo de ejecución, pienso en lo fantástico que sería si pudiera encontrarlo durante la compilación.
Rendimiento
De hecho, este siempre ha sido un punto en el que mucha gente se queja de Python, pero Python tiene sus propias cosas para las que es adecuado. Sería un poco difícil. usar Python para desarrollar algunos módulos de alto rendimiento es difícil.
El GIL de Python hace que sea imposible lograr un verdadero subproceso múltiple. Se puede decir que terminaré si uso múltiples procesos. Pero si algunos cálculos requieren interacción de múltiples procesos, también se debe considerar la sobrecarga de comunicación entre procesos.
Es muy conveniente utilizar múltiples procesos para el procesamiento distribuido sin estado. Por ejemplo, para procesar solicitudes http, montamos más de 200 servidores Django detrás de nginx para procesar http. En general, la carga de la máquina es alta.
Pero incluso si usamos múltiples procesos de Django para manejar solicitudes http, Python aún no puede manejar algunas solicitudes extremadamente grandes. Entonces usamos openresty para implementar solicitudes http de alta frecuencia usando lua. Pero esto lleva al uso de dos lenguajes de desarrollo y es necesario escribir cierta lógica en dos códigos diferentes.
Modelo de red sincrónica
La red de Django está bloqueada sincrónicamente, es decir, si necesitamos acceder a un servicio externo, Django no puede procesar ninguno mientras espera que se devuelva el resultado. Otra lógica (excepto para subprocesos múltiples, por supuesto). Si acceder a un servicio externo lleva mucho tiempo, eso significa que todo nuestro servicio estará casi completamente indisponible durante un largo período de tiempo.
Para resolver este problema, solo podemos continuar abriendo más procesos de Django y, al mismo tiempo, debemos asegurarnos de que todos los servicios puedan procesar las respuestas rápidamente, pero piénselo, en realidad esto es un cosa muy poco confiable.
Modelo de red asíncrono
El modelo de red de Tornado es asíncrono, lo que significa que no tendrá el problema de django de que el servicio no puede responder porque el servicio externo no está disponible. Por cierto, en comparación con Django, me gusta mucho Tornado. Es pequeño y simple. He escrito varios artículos sobre análisis en profundidad de Tornado.
Aunque tornado es asíncrono, la biblioteca mysql de Python no admite asíncrono, lo que significa que si accedemos a la base de datos en tornado, es posible que aún nos enfrentemos a que todo el servicio no esté disponible debido a problemas con la base de datos.
De hecho, el mayor problema con el modelo asincrónico es la separación de la lógica del código. Debido a que es activado por eventos, todos realizamos procesamiento relacionado a través de devoluciones de llamada. Por lo tanto, en el código, a menudo hacemos una cosa. y pasar una devolución de llamada Luego, la situación de devolución de llamada se pasa en la devolución de llamada. El resultado es que toda la lógica del código es muy confusa.
Python no tiene soporte nativo para corrutinas. Aunque las corrutinas se pueden admitir mediante métodos de parcheo como gevent y greenlet, después de todo, el código fuente de Python ha sido cambiado. Además
Además, el rendimiento de Python también puede realizar una simulación de rutina simple, pero después de todo, no puede cruzar pilas y tiene grandes limitaciones, no sé si se ha mejorado la versión 3.x.
Implementación de desarrollo, operación y mantenimiento
Cuando utilicé Python por primera vez para desarrollar un proyecto, no pude instalar correctamente los paquetes necesarios para el proyecto. La instalación tomó mucho tiempo. biblioteca mysql exitosamente. Más tarde, un colega empaquetó todo su directorio de Python para que yo lo usara y pude ejecutar el proyecto normalmente. Por cierto, ahora que tenemos Docker, es algo muy feliz.
Al implementar servicios de Python, necesitamos instalar un montón de paquetes en el servidor. Esto por sí solo es muy problemático. Aunque el problema de implementación se puede resolver mediante herramientas automatizadas como Puppet y Salt, es relativamente difícil. En comparación, los lenguajes compilados estáticamente solo necesitan generar un archivo binario, lo cual es mucho más conveniente.
El código está fuera de control
Python es muy flexible y sencillo. Las funciones que sólo se pueden resolver escribiendo decenas de líneas de código en C se pueden resolver con una sola línea. código en Python. Sin embargo, es demasiado simple, lo que impide que muchos estudiantes piensen profundamente en el código y consideren toda la arquitectura en detalle. Cuando surge un requisito, bang bang bang, presiono el teclado y comienzo a implementarlo rápidamente. El resultado es que el código se vuelve cada vez más confuso, lo que eventualmente hace que todo el código del proyecto se salga de control.
Aunque esto también tiene nuestras propias razones, como no tener un buen mecanismo de revisión de código y no tener buenas especificaciones de proyecto, personalmente creo que si un programador no ha recibido una buena formación en codificación, es fácil escribir en Python. Produce código incorrecto porque es demasiado gratuito.
Por supuesto, no estoy diciendo que el desarrollo de proyectos a gran escala no se pueda llevar a cabo con Python y Dropbox son buenos ejemplos. Es solo que en nuestro proyecto, nuestro código Python estaba fuera de control.
Los mencionados anteriormente son todos los problemas que encontramos al usar Python en proyectos reales. Aunque finalmente se resolvieron, siento cada vez más que a medida que aumenta la complejidad del proyecto, el rendimiento del tráfico se deteriorará. A medida que aumenta la presión, Python no es una buena opción.
Por qué elegir ir
Después de hablar de Python, ahora hablemos de por qué elegimos ir. De hecho, además de Python, también tenemos otras opciones, Java, PHP, Lua (openresty), pero al final elegimos ir.
Aunque Java y PHP son los mejores lenguajes de programación (todo el mundo discute sobre esto), prefiero un lenguaje más simple. Aunque Openresty tiene un rendimiento potente, Lua sigue siendo un lenguaje dinámico y encontrará algunos de los problemas de lenguaje dinámico mencionados anteriormente. Finalmente, el ex Jinshan Xu Shiwei usaba go, y el ex arquitecto de Kuaipan, Congtou, también usaba go, por lo que naturalmente elegimos ir.
go no es perfecto, hay muchas cosas de las que vale la pena quejarse.
Error, bueno, si eres un fanático de los idiomas, es posible que no puedas soportar la sintaxis de go, especialmente porque el último valor de retorno acordado es error. Los proyectos suelen estar llenos de código como este:
if _, err := w.Write(data1 err != nil {
returun err
}
if _, err := w.Write(data2); err != nil {
returun err
}
No es de extrañar que haya una broma sobre un requisito. Cuando los programadores de Java están escribiendo la configuración, los programadores de Go ya han escrito la mayor parte del código, pero cuando los programadores de Java terminan de escribir, los programadores de Go todavía están escribiendo err != nil .
En este sentido, errores-are-values recomienda una buena solución.
Administración de paquetes, la administración de paquetes de go es demasiado débil, solo hay un go
get, es decir, si actualiza accidentalmente una biblioteca externa, es muy probable que el código existente se dañará. No se puede compilar. Aunque ya existen muchas soluciones de código abierto, como godep y el recién lanzado gb, después de todo no son oficiales. Parece que Google también gestiona bibliotecas de terceros a través del mecanismo del proveedor. Espero que las versiones 1.5 o posteriores puedan manejar bien este problema.
GC, el GC de Java se ha desarrollado durante 20 años y go solo ha existido durante un tiempo, por lo que GC definitivamente no es perfecto. Por lo tanto, todavía no podemos escribir el código que queramos; de lo contrario, gc puede detener todo el servicio bajo un gran volumen de solicitudes. Entonces, a veces, se debe usar el grupo de objetos y el grupo de memoria. Aunque el código es un poco feo, el rendimiento ha mejorado.
Genéricos, aunque go tiene interfaz, la falta de genéricos nos hará escribir mucho código repetido al implementar una función, como los tipos int32 e int64, nosotros
Tú Tengo que escribir dos conjuntos de códigos por separado, lo cual es muy redundante. Después de go 1.4, hay soporte para go
generate, pero esto aún requiere que escribas manualmente el analizador relevante basado en la biblioteca AST de go, lo cual es bastante difícil. Aunque hay muchas implementaciones de código abierto de generate,
después de todo, no son oficiales.
Por supuesto, hay muchas cosas de las que vale la pena quejarse, así que no las enumeraré todas, pero Go aún tiene sus ventajas.
Lenguaje estático, fuertemente tipado. La compilación estática puede ayudarnos a verificar muchos errores. La escritura fuerte de Go es tan anormal que no admite la conversión de tipos implícita. Aunque escribir código resulta incómodo, reduce la posibilidad de cometer errores.
gofmt, este debería ser el primer idioma que conozco que proporciona oficialmente una herramienta de código de formato unificado. Con gofmt, el código de todos tiene el mismo aspecto y no hay discusiones molestas sobre el estilo del código, como si se deben poner las llaves al final o abrir una nueva línea. Como todos tienen el mismo estilo de codificación, es fácil leer el código Go.
Soporte paralelo innato. Debido a la rutina y el canal, es extremadamente fácil escribir aplicaciones distribuidas con programas concurrentes go and write. No hay fragmentación de la lógica del código causada por devoluciones de llamadas dolorosas, y toda la lógica del código es secuencial.
Rendimiento, el rendimiento de go puede no ser tan bueno como el de c, c++ y openresty, pero es realmente poderoso. En nuestro proyecto, el proceso one go ahora se implementa en una sola máquina, que es totalmente capaz de realizar el trabajo de los 200 procesos de Python anteriores, y el uso de CPU y MEM es menor.
Para la implementación de operación y mantenimiento, puede compilarlo directamente en un binario y lanzarlo en el servidor. Es mucho más simple que Python, que requiere la instalación de varios entornos. Por supuesto, si hay cgo, también debemos lanzar allí la biblioteca dinámica correspondiente.
Eficiencia del desarrollo. Aunque go es un lenguaje estático, personalmente creo que la eficiencia del desarrollo es realmente alta, y está a la par con Python.
Para mí personalmente, el mejor ejemplo es que usé Go para desarrollar rápidamente muchos componentes de código abierto, como ledisdb, go-mysql, etc., y todas estas versiones iniciales se completaron en muy poco tiempo. Para nuestro proyecto, también usamos go para reconstruir la primera versión en un mes y la lanzamos.