Warum hängt dieses Programm?
Feb 14, 2024 pm 03:06 PMDer PHP-Editor Xigua stößt häufig auf das Problem, dass das Programm während des Programmiervorgangs hängen bleibt. Programmabsturz bedeutet, dass das Programm während der Ausführung plötzlich nicht mehr reagiert, ohne dass eine Fehlermeldung erscheint. Diese Situation verwirrt die Menschen oft darüber, was falsch ist. Warum genau hängt dieses Programm? In diesem Artikel untersuchen wir einige häufige Ursachen für Programmabstürze und stellen Lösungen zur Behebung des Problems bereit. Egal, ob Sie Anfänger oder erfahrener Entwickler sind, ich glaube, dass diese Inhalte für Sie hilfreich sein können.
Frageninhalt
Ich habe Code für die Kommunikation zwischen Kanälen in Go. Es scheint zu tun, was es will, bleibt aber am Ende hängen. Ich versuche zu diagnostizieren, warum es hängt.
Der Code verwendet httpbin.org
, um eine zufällige UUID abzurufen und sie dann zu veröffentlichen, während die Parallelitäts- und Ratenbeschränkungen eingehalten werden, die ich über den Semaphorkanal und den Ratenkanal festgelegt habe.
package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "sync" "time" ) type HttpBinGetRequest struct { url string } type HttpBinGetResponse struct { Uuid string `json:"uuid"` StatusCode int } type HttpBinPostRequest struct { url string uuid string // Item to post to API } type HttpBinPostResponse struct { Data string `json:"data"` StatusCode int } func main() { // Prepare GET requests for n requests var requests []*HttpBinGetRequest for i := 0; i < 10; i++ { uri := "https://httpbin.org/uuid" request := &HttpBinGetRequest{ url: uri, } requests = append(requests, request) } // Create semaphore and rate limit for the GET endpoint getSemaphore := make(chan struct{}, 10) getRate := make(chan struct{}, 10) defer close(getRate) defer close(getSemaphore) for i := 0; i < cap(getRate); i++ { getRate <- struct{}{} } go func() { // ticker corresponding to 1/nth of a second // where n = rate limit // basically (1000 / rps) * time.Millisecond ticker := time.NewTicker(100 * time.Millisecond) defer ticker.Stop() for range ticker.C { _, ok := <-getRate if !ok { return } } }() // Send our GET requests to obtain a random UUID respChan := make(chan HttpBinGetResponse) var wg sync.WaitGroup for _, request := range requests { wg.Add(1) // cnt := c // Go func to make request and receive the response go func(r *HttpBinGetRequest) { defer wg.Done() // Check the rate limiter and block if it is empty getRate <- struct{}{} // fmt.Printf("Request #%d at: %s\n", cnt, time.Now().UTC().Format("2006-01-02T15:04:05.000Z07:00")) resp, _ := get(r, getSemaphore) fmt.Printf("%+v\n", resp) // Place our response into the channel respChan <- *resp // fmt.Printf("%+v,%s\n", resp, time.Now().UTC().Format("2006-01-02T15:04:05.000Z07:00")) }(request) } // Set up for POST requests 10/s postSemaphore := make(chan struct{}, 10) postRate := make(chan struct{}, 10) defer close(postRate) defer close(postSemaphore) for i := 0; i < cap(postRate); i++ { postRate <- struct{}{} } go func() { // ticker corresponding to 1/nth of a second // where n = rate limit // basically (1000 / rps) * time.Millisecond ticker := time.NewTicker(100 * time.Millisecond) defer ticker.Stop() for range ticker.C { _, ok := <-postRate if !ok { return } } }() // Read responses as they become available for ele := range respChan { postReq := &HttpBinPostRequest{ url: "https://httpbin.org/post", uuid: ele.Uuid, } go func(r *HttpBinPostRequest) { postRate <- struct{}{} postResp, err := post(r, postSemaphore) if err != nil { fmt.Println(err) } fmt.Printf("%+v\n", postResp) }(postReq) } wg.Wait() close(respChan) } func get(hbgr *HttpBinGetRequest, sem chan struct{}) (*HttpBinGetResponse, error) { // Add a token to the semaphore sem <- struct{}{} // Remove token when function is complete defer func() { <-sem }() httpResp := &HttpBinGetResponse{} client := &http.Client{} req, err := http.NewRequest("GET", hbgr.url, nil) if err != nil { fmt.Println("error making request") return httpResp, err } req.Header = http.Header{ "accept": {"application/json"}, } resp, err := client.Do(req) if err != nil { fmt.Println(err) fmt.Println("error getting response") return httpResp, err } // Read Response body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("error reading response body") return httpResp, err } json.Unmarshal(body, &httpResp) httpResp.StatusCode = resp.StatusCode return httpResp, nil } // Method to post data to httpbin func post(hbr *HttpBinPostRequest, sem chan struct{}) (*HttpBinPostResponse, error) { // Add a token to the semaphore sem <- struct{}{} defer func() { <-sem }() httpResp := &HttpBinPostResponse{} client := &http.Client{} req, err := http.NewRequest("POST", hbr.url, bytes.NewBuffer([]byte(hbr.uuid))) if err != nil { fmt.Println("error making request") return httpResp, err } req.Header = http.Header{ "accept": {"application/json"}, } resp, err := client.Do(req) if err != nil { fmt.Println("error getting response") return httpResp, err } // Read Response body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("error reading response body") return httpResp, err } json.Unmarshal(body, &httpResp) httpResp.StatusCode = resp.StatusCode return httpResp, nil }
Workaround
Sie lesen Inhalte über range
语句从代码末尾的 respchan
. Dieser Code wird erst beendet, wenn der Kanal geschlossen wird – was nach diesem Codeblock geschieht.
for ele := range respchan { // ... } wg.wait() close(respchan)
Das Programm wird also nie beendet – denn all diese Logik befindet sich in derselben Goroutine.
Um das Problem zu beheben und sicherzustellen, dass alle Datensätze verarbeitet werden, bevor das Programm beendet wird, belassen Sie den Kanallesecode in der Haupt-Goroutine und fügen Sie die Warte-/Schließlogik in die eigene Goroutine ein:
go func() { wg.wait() // wait for workers to finish ... close(respchan) // ... now signal the main goroutine we're done }() for ele := range respchan { // ... }
Bearbeiten um auf das Finale zu warten range
jede untergeordnete Goroutine in der Schleife – es gibt wahrscheinlich eine sauberere Möglichkeit, einfach eine Wartegruppe zu verwenden, aber eine schnelle Lösung könnte sein:
var swg sync.WaitGroup go func() { wg.Wait() // wait for workers to finish ... swg.Wait() // ... and sub-tasks close(respChan) // ... now signal the main goroutine we're done }() for ele := range respChan { // ... swg.Add(1) go func() { defer swg.Done() // ... }() }
Das obige ist der detaillierte Inhalt vonWarum hängt dieses Programm?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heißer Artikel

Hot-Tools-Tags

Heißer Artikel

Heiße Artikel -Tags

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

GO Language Pack Import: Was ist der Unterschied zwischen Unterstrich und ohne Unterstrich?

Wie kann ich kurzfristige Informationsübertragung zwischen Seiten im BeEGO-Framework implementieren?

Wie schreibe ich Scheinobjekte und Stubs zum Testen in Go?

Wie kann ich Tracing -Tools verwenden, um den Ausführungsfluss meiner GO -Anwendungen zu verstehen?

Wie konvertieren Sie die Liste der MySQL -Abfrageergebnisse in eine benutzerdefinierte Struktur -Slice in Go -Sprache?

Wie schreibe ich Dateien in Go Language bequem?

Wie kann ich benutzerdefinierte Typ -Einschränkungen für Generika in Go definieren?
