PHP 편집자 Xigua는 프로그래밍 과정에서 프로그램이 중단되는 문제에 자주 직면합니다. 프로그램 정지는 프로그램이 실행 중에 오류 메시지 없이 갑자기 응답을 멈추는 것을 의미합니다. 이러한 상황은 종종 사람들을 무엇이 잘못되었는지 혼란스럽게 만듭니다. 이 프로그램이 정확히 왜 중단되나요? 이 문서에서는 프로그램 중단의 몇 가지 일반적인 원인을 살펴보고 문제 해결에 도움이 되는 솔루션을 제공합니다. 초보자이시든, 숙련된 개발자이시든, 이 내용이 여러분에게 도움이 될 것이라고 믿습니다.
가서 채널간 통신할 수 있는 코드가 있습니다. 원하는 대로 수행되는 것처럼 보이지만 결국에는 멈춥니다. 왜 멈추는지 진단하려고 합니다.
코드는 httpbin.org
를 사용하여 임의의 uuid를 얻은 다음 세마포어 채널과 속도 채널을 통해 설정한 동시성 및 속도 제한을 준수하면서 이를 게시합니다.
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 }
range
语句从代码末尾的 respchan
을 통해 콘텐츠를 읽고 계십니다. 이 코드는 채널이 닫힐 때까지 종료되지 않습니다. 이는 이 코드 블록 이후에 발생합니다.
그래서 프로그램은 절대 종료되지 않습니다. 왜냐하면 이 모든 로직이 동일한 고루틴에 있기 때문입니다.
프로그램이 종료되기 전에 모든 레코드가 처리되도록 수정하고 확인하려면 채널 읽기 코드를 기본 고루틴에 유지하고 대기/닫기 로직을 자체 고루틴에 넣으세요.
으아악루프의 모든 하위 고루틴을 최종 기다리도록 편집 range
- 대기 그룹을 사용하는 더 깔끔한 방법이 있을 수 있지만 빠른 수정 방법은 다음과 같습니다.
위 내용은 이 프로그램이 왜 정지되나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!