2017-11-22 3 views
0

Ich habe ein Upload-Programm, das ich arbeite, und ich bin in ein Problem. Ich habe Routinen, die das Hochladen der Teile in eine große Datei übernehmen. Im Wesentlichen wird die Datei in 100 MB-Chunks aufgeteilt und gleichzeitig hochgeladen, abhängig von der Anzahl gleichzeitiger Prozesse, die Sie in der Konfiguration angeben.Erstellen von Slice-Byte-Goroutine hängt

Das Problem, das ich habe, ist, wenn ich einen Puffer erstellen, um die Datei zu lesen und laden Sie die make ([] Byte, 100000000) hängt ... aber nur, wenn es in einer Go-Routine ist. (Ich verwende 100000000, um die Upload-Berechnungen zu vereinfachen)

Hier ist ein Beispiel.

Dies funktioniert: https://play.golang.org/p/tkn8JVir9S

package main 

import (
    "fmt" 
) 

func main() { 
    buffer := make([]byte, 100000000) 
    fmt.Println(len(buffer)) 
} 

Dies gilt nicht: https://play.golang.org/p/H8626OLpqQ

package 

main 

import (
    "fmt" 
) 

func main() { 
    go createBuffer() 
    for { 
    } 

} 

func createBuffer() { 
    buffer := make([]byte, 100000000) 
    fmt.Println(len(buffer)) 
} 

Es hängt nur ... Ich bin nicht sicher, ob es eine Speicherbeschränkung für eine Go-Routine? Ich versuchte zu recherchieren und zu sehen, was ich finden konnte, aber nichts. Irgendwelche Gedanken würden geschätzt werden.

EDIT: Vielen Dank für das Feedback. Ich werde sagen, dass ich das wirkliche Problem nicht sehr gut erklärt habe und versuchen werde, das nächste Mal eine ganzheitliche Sichtweise zu bieten. Am Ende habe ich einen Kanal benutzt, um meine Gorino-Dateien für neue Dateien bereit zu halten. Dies ist für eine DR-Sicherung, die alle 3rd-Party-Dateien hochlädt, für die große Dateien in 100mb-Chunks aufgeteilt werden müssen. Ich denke, ich hätte mich über die Art meines Programms klar sein müssen.

+6

Sie haben eine beschäftigt Schleife in Ihrem Programm. Es gibt nie einen Grund, eine leere Schleife zu verwenden.Es verbraucht nur 100% einer CPU ohne Grund und wird schließlich die Laufzeit blockieren. – JimB

+0

Versuchen Sie 'select {}' anstelle von 'for {}' zu verwenden. Ist nicht der beste Ansatz (Sie sollten Kanäle dafür verwenden, um zu überprüfen, wenn die Go-Routinen fertig sind), aber zu Testzwecken ist es in Ordnung. – ajnavarro

+0

Das Zuweisen eines Byte-Slices in einer Goroutine ist in Ordnung, wie Sie hier sehen können https://play.golang.org/p/8QawOUTFyb, das Problem in Ihrem Beispiel, wie bereits von JimB aufgezeigt, ist die for-Schleife. – mkopriva

Antwort

1

Dieses Programm hängt, weil es in Ihrem Code eine Endlosschleife gibt. Versuchen Sie, den Code einfach so auszuführen, um es selbst zu beweisen. Die Goroutine ist nicht das, was das Aufhängen verursacht.

func main() { 
    for { 
    } 
} 

Wenn Sie nur fmt.Println(..) gedruckt sehen wollen, dann würde ich empfehlen, einen time.Sleep Anruf oder ähnliches haben.

Wenn Sie warten möchten, bis eine Gruppe von Goroutines abgeschlossen ist, dann würde ich this excellent answer genau diese Frage empfehlen.

+0

Nun, ich habe Dateien, die Dateien verarbeiten und offen bleiben müssen und weiterhin offen bleiben. Das Problem, das ich habe, ist die App als Daemon laufen und das hat dieses Problem ausgelöst. – MattA

+0

Sieht aus wie [dieser Beitrag] (https://stackoverflow.com/questions/23736046/how-to-create-a-daemon-process-in-golang) ist ein guter Ort, um zu starten, wenn Sie einen Daemon machen möchten . Das Hauptproblem besteht darin, dass Sie keine Busy-Wait-Schleife haben müssen, damit Sie keine CPU-Zyklen verschwenden. –

0

Package runtime

import "runtime" 

func Gosched

func Gosched() 

Gosched ergibt den Prozessor, so dass andere goroutines auszuführen. Es unterbricht die aktuelle Goroutine nicht, so dass die Ausführung automatisch fortgesetzt wird.


Wenn Sie etwas tun seltsame (for {} und 100MB), erhalten Sie seltsame Ergebnisse. Mach etwas Vernünftiges. Zum Beispiel

package main 

import (
    "fmt" 
    "runtime" 
) 

func main() { 
    go createBuffer() 
    for { 
     runtime.Gosched() 
    } 
} 

func createBuffer() { 
    buffer := make([]byte, 100000000) 
    fmt.Println(len(buffer)) 
} 

Ausgang:

100000000 
^Csignal: interrupt 
+0

Nun, ich habe mehrere Go-Routinen ausgeführt, die Dateien verarbeiten, von denen mehrere eine Konfiguration verwenden, um gleichzeitige Prozesse zu bestimmen. Das Problem ist, dass ich eine Datei in 100MB Chucks schneiden muss, um über einen HTTP-Post zu senden, so dass die 100MB nicht seltsam ist. Soweit die for-Schleife dieses Problem verschwunden ist, und jetzt weiß ich warum, wenn ich meinen Kanal hinzugefügt, um die fertigen Dateien zurückzugeben. – MattA

+0

@MattA: Ihr Beispiel ist sehr erfunden. Dein Fall in der realen Welt ist anders. Außerdem ist die Verwendung von 100 MB Speicher pro Chunk zum gleichzeitigen Senden von 100 MB Chunks ineffizient. Wie viel Speicher benötigen Sie, um 10.000 Benutzer zu unterstützen? Sie brauchen eine bessere Strategie. Google verwendet Go intern zum Herunterladen: [dl.google.com wird jetzt von Go bereitgestellt] (https://groups.google.com/forum/#!topic/golang-nuts/BNUNbKSypE0) und [dl.google.com: Powered von Go] (https://talks.golang.org/2013/oscon-dl.slide#1). – peterSO

+0

Ich stimme zu, ich hätte ein wenig expliziter mit dem genauen Thema sein sollen und warum ich es gemacht habe. Ich war neugierig auf den Grund und jetzt, da ich die Antworten sehe, macht es Sinn. Ich muss tatsächlich einen Kanal haben, der blockiert und wir lassen die Goroutines fortfahren, bis ein Fehler auftritt. Soweit es die Ineffizienz betrifft, ist dies ein Upload-Dienstprogramm zu einem DR-Backup-Anbieter, so dass es keine Benutzer gibt. Sie können maximal gleichzeitige Prozesse in der Konfigurationsdatei definieren, und dies ist die Grenze für den Speicherverbrauch. Die DR-API erfordert, dass große Dateien in Blöcke aufgeteilt und im Hauptteil eines POST gesendet werden. – MattA