¿Cómo hacer más rápido una llamada de API en Golang?
Estoy tratando de subir un montón de archivos utilizando la api de la empresa al servicio de almacenamiento que proporcionan (básicamente a mi cuenta). Tengo muchos archivos, como 40-50 o algo así.
Tengo la ruta completa de los archivos y utilizo os.Open
, para que pueda pasar el io.Reader
. Intenté usar client.Files.Upload()
sin goroutines
, pero tardó mucho tiempo en subirlos y decidí usar goroutines
. Aquí está la implementación que intenté. Cuando ejecuto el programa, solo sube un archivo que es el que tiene el tamaño más bajo o algo así que espera mucho tiempo. ¿Qué está mal con esto? ¿No es así que cada vez que se ejecuta el bucle for crea una goroutine
, continúa su ciclo y crea una para cada file
? ¿Cómo hacerlo lo más rápido posible con goroutines
?
var filePaths []string
var wg sync.WaitGroup
// Llena el slice de strings con la ruta completa de los archivos.
func fill() {
filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
filePaths = append(filePaths, path)
}
if err != nil {
fmt.Println("ERROR:", err)
}
return nil
})
}
func main() {
fill()
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
oauthClient := oauth2.NewClient(context.TODO(), tokenSource)
client := putio.NewClient(oauthClient)
for _, path := range filePaths {
wg.Add(1)
go func() {
defer wg.Done()
f, err := os.Open(path)
if err != nil {
log.Println("err:OPEN", err)
}
upload, err := client.Files.Upload(context.TODO(), f, path, 0)
if err != nil {
log.Println("error uploading file:", err)
}
fmt.Println(upload)
}()
}
wg.Wait()
}
davy.ai
El problema con la implementación actual es que todas las goroutines están intentando leer del mismo recurso, lo cual está causando una condición de carrera. Dado que las tareas están limitadas por la E/S, crear demasiadas goroutines puede ralentizar el proceso. En lugar de crear una goroutine para cada archivo, podemos limitar el número de cargas de archivos concurrentes utilizando un canal y un enfoque de grupo de trabajadores. Aquí tenemos una implementación modificada:
En esta implementación, limitamos el número de goroutines que pueden ejecutarse simultáneamente a
numWorkers
, que se establece en 10. Utilizamos unchan struct{}
para crear un mecanismo similar a un semáforo y limitar el número de goroutines que pueden acceder al recurso compartido (la API de red en este caso). La funciónuploadFile
envuelve la lógica de carga de archivos y libera una ranura en el canal después de que se complete cada carga de archivo.Ten en cuenta que aún necesitamos esperar a que todas las cargas de archivos se completen al final de la función
main
. Logramos esto bloqueando en el canalnumWorkers
veces.