第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

如何返回第一個(gè)http響應(yīng)來回答

如何返回第一個(gè)http響應(yīng)來回答

Go
元芳怎么了 2023-07-31 15:14:59
我使用多個(gè) goroutine 來運(yùn)行任務(wù),當(dāng)其中一個(gè)完成時(shí),返回并關(guān)閉通道,這將導(dǎo)致恐慌:在關(guān)閉的通道上發(fā)送。參見代碼:func fetch(urls []string) *http.Response {    ch := make(chan *http.Response)    defer close(ch)    for _, url := range urls {        go func() {            resp, err := http.Get(url)            if err == nil {                ch <- resp            }        }()    }    return <-ch}如果不關(guān)閉通道是沒有問題的,但是我覺得不太好,那么有什么優(yōu)雅的解決方案嗎?感謝您的所有回答,這是我的最終代碼:func fetch(urls []string) *http.Response {    var wg sync.WaitGroup    ch := make(chan *http.Response)    wg.Add(len(urls))    for _, url := range urls {        go func(url string) {            defer wg.Done()            resp, err := http.Get(url)            if err == nil {                ch <- resp            }        }(url)    }    go func() {        wg.Wait()        close(ch)    }()    return <-ch}
查看完整描述

6 回答

?
白板的微信

TA貢獻(xiàn)1883條經(jīng)驗(yàn) 獲得超3個(gè)贊

在此版本中,通道ch有足夠的空間,以便在相應(yīng)的通道讀取器不存在的情況下,例程可以推送到它而不會(huì)阻塞。


package main


import (

    "fmt"

    "net/http"

    "sync"

)


func main() {

    urls := []string{"", "", ""}

    res := fetch(urls)

    fmt.Println(res)

}

func fetch(urls []string) *http.Response {

    var wg sync.WaitGroup

    ch := make(chan *http.Response, len(urls))


    for _, url := range urls {

        wg.Add(1)

        url := url

        go func() {

            defer wg.Done()

            req, err := http.NewRequest(http.MethodGet, url, nil)

            if err != nil {

                return

            }

            resp, err := http.DefaultClient.Do(req)

            if err != nil {

                return

            }

            if resp != nil {

                ch <- resp // no need to test the context, ch has rooms for this push to happen anyways.

            }

        }()

    }


    go func() {

        wg.Wait()

        close(ch)

    }()


    return <-ch

}

https://play.golang.org/p/5KUeaUS2FLg

context此版本說明了附加到取消請(qǐng)求的實(shí)現(xiàn)。

package main


import (

    "context"

    "fmt"

    "net/http"

    "sync"

)


func main() {

    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    cancel()

    urls := []string{"", "", ""}

    res := fetch(ctx, urls)

    fmt.Println(res)

}


func fetch(ctx context.Context, urls []string) *http.Response {

    var wg sync.WaitGroup

    ch := make(chan *http.Response, len(urls))

    for _, url := range urls {

        if ctx.Err() != nil {

            break // break asap.

        }

        wg.Add(1)

        url := url

        go func() {

            defer wg.Done()

            req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)

            if err != nil {

                return

            }

            resp, err := http.DefaultClient.Do(req)

            if err != nil {

                return

            }

            if resp != nil {

                ch <- resp // no need to test the context, ch has rooms for this push to happen anyways.

            }

        }()

    }

    go func() {

        wg.Wait()

        close(ch)

    }()

    return <-ch

}

https://play.golang.org/p/QUOReYrWqDp


友情提醒,不要試圖太聰明,使用a sync.WaitGroup,用最簡(jiǎn)單的邏輯編寫流程并讓它流動(dòng),直到您可以安全地close通過該通道。


查看完整回答
反對(duì) 回復(fù) 2023-07-31
?
白豬掌柜的

TA貢獻(xiàn)1893條經(jīng)驗(yàn) 獲得超10個(gè)贊

如果您的目標(biāo)是只讀取一個(gè)結(jié)果,然后取消其他請(qǐng)求,請(qǐng)嘗試如下操作:


func fetch(urls []string) *http.Response {

    ch := make(chan *http.Response)

    defer close(ch)

    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    for _, url := range urls {

        go func(ctx context.Context, url string) {

            req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)

            resp, err := http.Do(req)

            if err == nil {

                select {

                case ch <- resp:

                case <- ctx.Done():

                }

            }

        }(ctx, url)

    }

    return <-ch

}

這使用了可取消的上下文,因此一旦返回第一個(gè)結(jié)果,其余的 http 請(qǐng)求就會(huì)發(fā)出中止信號(hào)。


注意:您的代碼有一個(gè)錯(cuò)誤,我已在上面修復(fù):


func _, url := range urls {

    go func() {

        http.Do(url) // `url` is changed here on each iteration through the for loop, meaning you will not be calling the url you expect

    }()

}

通過傳遞url給 goroutine 函數(shù)來修復(fù)此問題,而不是使用閉包:


func _, url := range urls {

    go func(url string) {

        http.Do(url) // `url` is now safe

    }(url)

}


查看完整回答
反對(duì) 回復(fù) 2023-07-31
?
一只萌萌小番薯

TA貢獻(xiàn)1795條經(jīng)驗(yàn) 獲得超7個(gè)贊

您太早關(guān)閉通道,這就是為什么您會(huì)看到此錯(cuò)誤,

最好僅當(dāng)您不再向通道寫入任何內(nèi)容時(shí)才關(guān)閉通道,為此您可以使用sync.WaitGroup,如下所示:


package main


import (

    "fmt"

    "net/http"

    "sync"

)


func main() {

    ch := fetch([]string{"http://github.com/cn007b", "http://github.com/thepkg"})

    fmt.Println("\n", <-ch)

    fmt.Println("\n", <-ch)

}


func fetch(urls []string) chan *http.Response {

    ch := make(chan *http.Response, len(urls))

    wg := sync.WaitGroup{}

    wg.Add(len(urls))

    for _, url := range urls {

        go func() {

            defer wg.Done()

            resp, err := http.Get(url)

            if err == nil {

                ch <- resp

            }

        }()

    }

    go func() {

        wg.Wait()

        close(ch)

    }()

    return ch

}

另外,為了提供帶有響應(yīng)的切片,您可以執(zhí)行以下操作:


func fetch2(urls []string) (result []*http.Response) {

    ch := make(chan *http.Response, len(urls))

    wg := sync.WaitGroup{}

    wg.Add(len(urls))

    for _, url := range urls {

        go func() {

            defer wg.Done()

            resp, err := http.Get(url)

            if err == nil {

                ch <- resp

            }

        }()

    }

    wg.Wait()

    close(ch)

    for v := range ch {

        result = append(result, v)

    }

    return result

}


查看完整回答
反對(duì) 回復(fù) 2023-07-31
?
繁花不似錦

TA貢獻(xiàn)1851條經(jīng)驗(yàn) 獲得超4個(gè)贊

您最后推薦的代碼僅在您的至少一個(gè)調(diào)用成功時(shí)才有效。如果您進(jìn)行的每個(gè) HTTP GET 都出現(xiàn)錯(cuò)誤,您的函數(shù)將永遠(yuǎn)阻塞。您可以添加第二個(gè)渠道來通知您呼叫已完成:


func fetch(urls []string) *http.Response {

    var wg sync.WaitGroup

    ch := make(chan *http.Response, len(urls))

    done := make(chan struct{})

    wg.Add(len(urls))

    for _, url := range urls {

        go func(url string) {

            defer wg.Done()

            resp, err := http.Get(url)

            // only put a response into the channel if we didn't get an error

            if err == nil {

                ch <- resp

            }

        }(url)

    }

    go func() {

        wg.Wait()

        // inform main routine that all calls have exited

        done <- struct{}{}

        close(ch)

    }()


    // return either the first response or nil

    select {

        case r := <-ch:

        return r

        case <-done:

        break

   }


   // you can do additional error handling here

   return nil

}


查看完整回答
反對(duì) 回復(fù) 2023-07-31
?
MM們

TA貢獻(xiàn)1886條經(jīng)驗(yàn) 獲得超2個(gè)贊

您的代碼將在收到第一個(gè)響應(yīng)后返回。然后關(guān)閉通道,讓其他 go 例程在關(guān)閉的通道上發(fā)送。


與其返回第一個(gè)響應(yīng),不如返回一組響應(yīng),并以與 url 相同的長(zhǎng)度排序,這可能更合適。


由于 http 請(qǐng)求可能會(huì)出錯(cuò),因此明智的做法是返回一組錯(cuò)誤。


package main


import (

    "fmt"

    "net/http"

)


func main() {

    fmt.Println(fetch([]string{

        "https://google.com",

        "https://stackoverflow.com",

        "https://passkit.com",

    }))

}


type response struct {

    key      int

    response *http.Response

    err      error

}


func fetch(urls []string) ([]*http.Response, []error) {

    ch := make(chan response)

    defer close(ch)

    for k, url := range urls {

        go func(k int, url string) {

            r, err := http.Get(url)

            resp := response {

                key:      k,

                response: r,

                err:      err,

            }

            ch <- resp

        }(k, url)

    }


    resp := make([]*http.Response, len(urls))

    respErrors := make([]error, len(urls))


    for range urls {

        r := <-ch

        resp[r.key] = r.response

        respErrors[r.key] = r.err

    }

    return resp[:], respErrors[:]

}

操場(chǎng)


查看完整回答
反對(duì) 回復(fù) 2023-07-31
?
千巷貓影

TA貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超7個(gè)贊

您可以添加兩個(gè) goroutine:

  1. 接收所有請(qǐng)求,發(fā)送第一個(gè)要返回的請(qǐng)求并丟棄后續(xù)請(qǐng)求。當(dāng) WaitGroup 完成時(shí),它會(huì)關(guān)閉您的第一個(gè)通道。

  2. 一個(gè)等待 WaitGroup 并發(fā)送信號(hào)以關(guān)閉第一個(gè)通道。

func fetch(urls []string) *http.Response {

    var wg sync.WaitGroup

    ch := make(chan *http.Response)

    for _, url := range urls {

        wg.Add(1)

        go func(url string) {

            resp, err := http.Get(url)          

            if err == nil {

                ch <- resp:

            }

            wg.Done()

        }(url)

    }

    done := make(chan interface{})

    go func(){

        wg.Wait()

        done <- interface{}{}

        close(done)

    }


    out := make(chan *http.Response)

    defer close(out)

    go func(){

        first = true

        for {

            select {

            case r <- ch:

                if first {

                    first = false

                    out <- r

                }

            case <-done:

                close(ch)

                return

            }

        }

    }()


    return <-out

}

這應(yīng)該是安全的……也許吧。


查看完整回答
反對(duì) 回復(fù) 2023-07-31
  • 6 回答
  • 0 關(guān)注
  • 248 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)