Golang - Есть проблемы с Go-процедурами и каналами - PullRequest
0 голосов
/ 19 октября 2018

Я немного новичок в Golang и пытаюсь разработать программу, которая загружает изображения асинхронно в imgur.Однако у меня есть некоторые трудности с моим кодом.

Так что это моя задача;

func uploadT(url string,c chan string, d chan string)  {

    var subtask string
    subtask=upload(url)

    var status string
    var url string

    if subtask!=""{
        status = "Success!"
        url =subtask

    } else {
        status = "Failed!"
        url =subtask
    }

    c<-url
    d<-status
}

А вот мой цикл запроса POST для асинхронной загрузки;

c:=make(chan string, len(js.Urls))
d:=make(chan string, len(js.Urls))

wg:=sync.WaitGroup{}
for i := range js.Urls{
    wg.Add(1)
    go uploadTask(js.Urls[i],c,d)
    //Below commented out code is slowing down the routine therefore, I commented out.
    //Needs to be working as well, however, it can work if I put this on task as well. I think I'm kinda confused with this one as well
    //pol=append(pol,retro{Url:<-c,Status:<-d})
}
<-c
<-d
wg.Done()
FinishedTime := time.Now().UTC().Format(time.RFC3339)
qwe=append(qwe,outputURLs{
               jobID:jobID,
               retro:pol,
               CreateTime: CreateTime,
               FinishedTime: FinishedTime,
           })
fmt.Println(jobID)

Так что я думаю, что мои каналы и рутина не работает.Распечатывает jobID перед загрузкой.А также загрузка кажется слишком медленной для асинхронной загрузки.

Я знаю, что код вроде как беспорядок, извините за это.Любая помощь высоко ценится!Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Ваш код немного запутанный.Но если я правильно понимаю, что вы пытаетесь сделать, вы обрабатываете список запросов и хотите вернуть URL-адрес и статус каждого запроса, а также время выполнения каждого запроса.И вы хотите обрабатывать их параллельно.

Вам вообще не нужно использовать WaitGroups.WaitGroups хороши, когда вы просто хотите запустить кучу задач, не заботясь о результатах, просто хотите знать, когда все будет сделано.Но если вы возвращаете результаты, каналов достаточно.

Вот пример кода, который делает то, что я думаю, вы пытаетесь сделать

package main

import (
    "time"
    "fmt"
)

type Result struct {
    URL      string
    Status   string
    Finished string
}

func task(url string, c chan string, d chan string) {
    time.Sleep(time.Second)
    c <- url
    d <- "Success"
}

func main() {
    var results []Result
    urls := []string{"url1", "url2", "url3", "url4", "url5"}
    c := make(chan string, len(urls))
    d := make(chan string, len(urls))
    for _, u := range urls {
        go task(u, c, d)
    }
    for i := 0; i < len(urls); i++ {
        res := Result{}
        res.URL = <-c
        res.Status = <-d
        res.Finished = time.Now().UTC().Format(time.RFC3339)
        results = append(results, res)
    }
    fmt.Println(results)
}

Вы можете попробовать это на детской площадке https://play.golang.org/p/N3oeA7MyZ8L

Тем не менее, это немного хрупко.Вы делаете каналы того же размера, что и ваш список URL.Это будет хорошо работать для нескольких URL, но если у вас есть список из миллиона URL, вы создадите довольно большой канал.Возможно, вы захотите установить разумный размер буфера канала и проверить, готов ли канал к обработке перед отправкой вашего запроса.Таким образом, вы не будете делать миллион запросов одновременно.

0 голосов
/ 19 октября 2018

Вы на самом деле не используете WaitGroup правильно.Каждый раз, когда вы вызываете wg.Done(), это фактически вычитает 1 из предыдущего wg.Add, чтобы определить, что задание выполнено.Наконец, вам понадобится wg.Wait() для синхронного ожидания всех задач.WaitGroups обычно используется для одновременного запуска нескольких задач.

Самый простой способ, основанный на вашем примере кода, - передать wg в вашу задачу, uploadT и вызвать wg.Done()внутри задачи.Обратите внимание, что вы также захотите использовать указатель вместо значения структуры.

Следующая деталь реализации заключается в вызове wg.Wait() вне цикла, потому что вы хотите блокировать, пока все задачи не будут выполнены, поскольку все ваши задачи выполняются с go, что делает его асинхронным.Если вы не wg.Wait(), он сразу же зарегистрирует jobID, как вы сказали.Дайте мне знать, если это ясно.

Как шаблон, он должен выглядеть примерно так

func task(wg *sync.WaitGroup) {
    wg.Done()
}

wg := &sync.WaitGroup{}
for i := 0; i < 10; i++ {
    wg.Add(1)
    go task(wg)
}

wg.Wait()
// do something after the task is done
fmt.Println("done")

Еще одна вещь, которую я хочу отметить, это то, что в вашем текущем примере кода выВы используете каналы, но вы ничего не делаете со значениями, которые вы вставляете в каналы, чтобы вы могли технически удалить их.

...