Liberar recursos en GO

Go es un lenguaje con gestión automática de memoria: el recolector de basura, sin necesidad de un programador, se encarga de recuperar la memoria utilizada por los objetos que ya no utiliza el programa. Pero toda la automatización en su conjunto está limitada por la memoria; todavía tenemos que encargarnos del resto de los recursos que utiliza el programa nosotros mismos.





Fuente de la imagen: http://kenimation.net/doctor-who%E2%80%AC-dalek/
Fuente de la imagen: http://kenimation.net/doctor-who%E2%80%AC-dalek/

, - , runtime.SetFinalizer. , , . Go - , , , , .





, - . , , - , .





res1, err := NewResource1()
if err != nil {
    return nil, err
}

res2, err := NewResource2(res1)
if err != nil {
  res1.Close()
  return nil, err
}

res3, err := NewResource3(res2)
if err != nil {
  res2.Close()
  res1.Close()
  return nil, err
}

v, err := res3.DoSomething()
if err != nil {
  res3.Close()
  res2.Close()
  res1.Close()
  return nil, err
}

res3.Close()
res2.Close()
res1.Close()
return v, nil
      
      



, . , ( ). Close , - .





. , C# Java using statement try-with-resources statement . Go , , defer statement. , :





res1, err := NewResource1()
if err != nil {
  return nil, err
}
defer res1.Close()

res2, err := NewResource2(res1)
if err != nil {
  return nil, err
}
defer res2.Close()

res3, err := NewResource3(res2)
if err != nil {
  return nil, err
}
defer res3.Close()

return res3.DoSomething()
      
      



Close . Close - .





, . - defer . , , - , . , , . , , - , - - , (, main), , , , , .





, Wire. ( Wire) . . cleanup function, . .





Dedicated finalization

, c cleanup function, Wire, . , Close ( ) :





  • ;





  • .





, , , . , Go :





res, cleanup, err := NewResource()
if err != nil {
  return err
}
//    cleanup,     .

if err := res.DoSomething(); err != nil {
  return err
}
      
      



, (, ) ( ) . , " ", , , "" "" , .





Composite finalization

defer (, ), :





func Finalize(finalizers ...func()) {
  //     .
  for i := len(finalizers) - 1; i >= 0; i-- {
    func() {
      defer func() {
        //      ,    .
        //        multierror :
        // 1)    ;
        // 2)    .
        recover()
      }()
      finalizers[i]()
    }()
  }
}

func NewResource3() (*Resource3, func(), error) {
  var (
    finalizers []func() //    
    successful bool     //    
  )
  defer func() {
    //       ,
    //        -
    //       .
    if !successfull {
      Finalize(finalizers...)
    }
  }()
  
  res1, fin1, err := NewResource1()
  if err != nil {
    return nil, nil, err
  }
  finalizers = append(finalizers, fin1)
  
  res2, fin2, err := NewResource2(res1)
  if err != nil {
    return nil, nil, err
  } 
  finalizers = append(finalizers, fin2)
  
  res3 := &Resource3{
    resource2: res2,
  }
  fin3 := func() {
    Finalize(finalizers...)
  }
  
  //        .
  //        
  //     .
  successful = true
  return res3, fin3, nil
}
      
      



Finalize - .





new - error - defer , , , , .





KDone

He publicado la biblioteca KDone que proporciona el conjunto de herramientas anterior. Ella es parte del proyecto Kata , que se discutirá a continuación. Podemos suponer que en este momento su API es estable y si cambia, será insignificante; sin embargo, la biblioteca aún está fresca y todavía uso la versión principal cero en caso de cambios imprevistos.





Un constructor típico que usa esta biblioteca se ve así:





func NewResource(...) (res Resource, dtor kdone.Destructor, err error) {
  
  defer kerror.Catch(&err)               //    
                                         //   KError.
                                         //    .
  
  reaper := kdone.NewReaper()            //  reaper.
  defer reaper.MustFinalize()            //   
                                         //   .
  
  // ... reaper.MustAssume(dtor) ...     //   reaper 
                                         //    
                                         // .
  
  return res, reaper.MustRelease(), nil  //  reaper  
                                         //      
                                         //  .
}
      
      



¿Qué piensas? El concepto es bastante simple, pero ¿tal vez me perdí algo en mi razonamiento? ¿O tiene sugerencias de mejoras? Me alegraría tener discusiones en los comentarios.








All Articles