Ir al esquema de implementación de singleton

Todo el mundo conoce bien el patrón singleton y se define de la siguiente manera: una clase solo puede crear un solo objeto (o instancia), entonces esta clase es una clase singleton. Este patrón de diseño se llama patrón de diseño singleton o singleton patrón para abreviar.

Aunque el modo singleton es relativamente sencillo de entender, hay muchos detalles que deben tenerse en cuenta cuando se implementa realmente. Las consideraciones generales son las siguientes:

  1. El constructor debe tener derechos de acceso privados, para evitar la creación externa de instancias a través de nuevos

  2. Considere los problemas de seguridad de los subprocesos al crear objetos

  3. Considere si es compatible con la carga diferida

  4. Considere si el rendimiento de getInstance () es alto (ya sea para bloquear o no)

Código

La gramática es diferente, el grado de atención a estos puntos también es diferente. Para el idioma Go, aquí hay una forma de escribir, usando sync.Once.Do. El propósito de esta función es ejecutarla solo una vez.

Entonces podemos escribir:

type Single struct {
    
    

}
var (
   once sync.Once
   single     *Single
)


func GetSingleInstance() *Single {
    
    
   once.Do(func() {
    
    
      single = &Single{
    
    }
   })
   return single
}

No importa cuántas solicitudes, solo habrá una instancia de Single.

prueba

Ahora pensemos en un escenario: si 100 solicitudes de repente solicitan la interfaz GetSingleInstance al mismo tiempo, ¿estas solicitudes esperarán a que Do se ejecute o simplemente devolverán una sola, independientemente de Do?

Teóricamente, debe esperar a que se complete la ejecución de Do; de lo contrario, el single devuelto está vacío, lo que provocará un error grave. Aunque creas que sí, hagamos una prueba.

package main

import (
   "fmt"
   "strconv"
   "sync"
   "time"
)

func main() {
    
    
   var once sync.Once
   onceBody := func() {
    
    
      fmt.Println("Only once start")
      time.Sleep(time.Second * 5)
      fmt.Println("Only once end")
   }

   for i := 0; i < 5; i++ {
    
    
      j := i
      go func(int) {
    
    
         fmt.Println(j)
         once.Do(onceBody)
         fmt.Println("lll" + strconv.Itoa(j))
      }(j)

   }
   fmt.Println("finished")
   time.Sleep(time.Second * 10)
}

El plan de prueba es muy simple, inicie 5 goroutines, llame a Do al mismo tiempo, una vez que Body se ponga en reposo durante 5 segundos, solo verifique la salida, puede juzgar si se bloqueará.

Los resultados de la ejecución son los siguientes:

➜ myproject ir a ejecutar main.go
terminado
0
Solo una vez inicio
2
4
3
1
Solo una vez final
lll2
lll4
lll0
lll1
lll3

Se puede ver que todas las goroutines se generarán solo después de que se ejecute Do, lo que demuestra que se llamará a Do, pero solo una se ejecutará realmente. Antes de que se complete la ejecución real, se bloquearán otras goroutines.

De hecho, existe un riesgo oculto: si la función ejecutada por Do consume mucho tiempo, provocará la acumulación de una gran cantidad de goroutines, lo que debe tenerse en cuenta a la hora de programar.

Implementación

¿Cómo se implementa la función Do? Echemos un vistazo al código fuente:

func (o *Once) Do(f func()) {
    
    
   if atomic.LoadUint32(&o.done) == 0 {
    
    
      // Outlined slow-path to allow inlining of the fast-path.
      o.doSlow(f)
   }
}
func (o *Once) doSlow(f func()) {
    
    
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
    
    
		defer atomic.StoreUint32(&o.done, 1)
		f()
	}
}

Cuando varias goroutines comprueban que el valor hecho es 0, ingrese doSlow, solo una goroutine obtendrá el bloqueo y otras goroutines no se bloquearán.

Las prácticas son tecnologías más convencionales, principalmente cerraduras de exclusión mutua, semáforos y aplazamiento, pero el diseño sigue siendo muy inteligente. Esto también es una ventaja de Go. El uso de bloqueos para resolver conflictos es rápido, seguro y conveniente, pero se deben considerar los problemas de rendimiento.

Por fin

Si te gusta mi artículo, puedes seguir mi cuenta oficial (Programador Mala Tang)

Mi blog personal es: https://shidawuhen.github.io/

Revisión de artículos anteriores:

tecnología

  1. Ir patrón de diseño (4) -escritura de código
  2. Ir patrón de diseño (3) -principios de diseño
  3. Ir al patrón de diseño (2) -análisis y diseño orientado a objetos
  4. Problemas generales de acceso a los pagos
  5. Tutorial básico de HTTP2.0
  6. Ir patrón de diseño (1) -gramática
  7. Especificación de desarrollo de MySQL
  8. Combate de configuración HTTPS
  9. Principios de la implementación del canal Go
  10. Ir al principio de implementación del temporizador
  11. Proceso de conexión HTTPS
  12. Realización del límite de corriente 2
  13. Sistema de picos
  14. Sistema distribuido y protocolo de consenso
  15. Marco de servicio y registro de microservicios
  16. Uso del marco de Beego
  17. Hablando de microservicios
  18. Optimización del rendimiento de TCP
  19. Realización del límite de corriente 1
  20. Redis implementa bloqueos distribuidos
  21. Seguimiento de errores del código fuente de Golang
  22. El principio de realización de la atomicidad, la coherencia y la durabilidad de las transacciones.
  23. Proceso de solicitud de CDN detallado
  24. Técnicas comunes de almacenamiento en caché
  25. Cómo conectarse de manera eficiente con pagos de terceros
  26. Versión concisa del marco de gin
  27. Un breve análisis de los bloqueos y transacciones de InnoDB
  28. Resumen del algoritmo

notas de estudio

  1. en principio
  2. Zi Zhi Tong Jian
  3. Revolución ágil
  4. Cómo ejercitar tu memoria
  5. Lógica simple después de la lectura
  6. Aire caliente después de la lectura
  7. Las Analectas-Pensamientos después de la lectura
  8. El arte de la guerra de Sun Tzu: pensamientos después de leer

Pensando

  1. Contra el liberalismo
  2. Teoría de la práctica
  3. Evaluar los propios estándares
  4. Plan de servicio de vacaciones del equipo servidor
  5. Gestión de procesos de proyectos
  6. Algunas opiniones sobre la gestión de proyectos
  7. Algunas reflexiones sobre los gerentes de producto
  8. Reflexiones sobre el desarrollo profesional de los programadores
  9. Pensando en la revisión del código
  10. Recomendación del editor de Markdown-typora

Supongo que te gusta

Origin blog.csdn.net/shida219/article/details/114818645
Recomendado
Clasificación