Praktykując wyzwanie, aby obliczyć terenki, podzielanie obliczeń na 100 grup jednocześnie, rozwiązałem wiele emisji na temat grup oczekiwania, ale nadal w funkcji calculateFactorial Mam zakleszczenie w zakresie na części kanału. Szkoda, że ktoś może skierować problem tutaj, dziękuję.

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    in := make (chan int)
    out := make (chan float64)



    out = calculateFactorial(genConcurrentGroup(in, &wg), &wg)

    go func() {
        in <- 10
        close(in)
    }()

    fmt.Println(<-out)

    wg.Wait()


}

//split input number into groups
//the result should be a map of [start number, number in group]
//this is not heavy task so run in one go routine
func genConcurrentGroup(c chan int, wg *sync.WaitGroup) chan map[int]int{
    out := make(chan map[int]int)

    go func() {
        //100 groups
        total:= <- c
        wg.Done()
        //element number in group
        elemNumber := total / 100
        extra := total % 100
        result := make(map[int]int)
        if elemNumber>0{
            //certain 100 groups
            for i:=1 ;i<=99;i++{
                result[(i-1) * elemNumber + 1] = elemNumber
            }
            result[100] = extra + elemNumber
        }else{
            //less than 100
            for i:=1;i<=total;i++{
                result[i] = 1
            }
        }

        out <- result
        close(out)
    }()
    return out
}

//takes in all numbers to calculate multiply result
//this could be heavy so can do it 100 groups together
func calculateFactorial(nums chan map[int]int, wg *sync.WaitGroup) chan float64{
    out := make(chan float64)


    go func() {
        total:= <- nums
        wg.Done()
        fmt.Println(total)

        oneResult := make(chan float64)

        var wg2 sync.WaitGroup
        wg2.Add(len(total))

        for k,v := range total{
            fmt.Printf("%d %d \n",k,v)
            go func(k int, v int) {
                t := 1.0
                for i:=0;i<v;i++{
                    t = t * (float64(k) + float64(i))
                }
                fmt.Println(t)
                oneResult <- t
                wg2.Done()
            }(k,v)
        }

        wg2.Wait()
        close(oneResult)

        result := 1.0
        for n := range oneResult{  //DEADLOCK HERE! Why?
            result *= n
        }


        fmt.Printf("Result: %f\n",result)

        out <- result

    }()
    return out
}

Aktualizacja :

Dzięki odpowiedziach Jessé Catrinck, który naprawił problem w powyższym kodzie, po prostu zmień oneResult do buforowanego kanału. Jednak w https://stackoverflow.com/a/15144455/921082 Jest cytat

Nigdy nie powinieneś dodawać buforowania, aby naprawić zakleszczenie. Jeśli masz zakleszczenie programu, znacznie łatwiej jest naprawić, począwszy od zera buforowania i przemyślenia przez zależności. Następnie dodaj buforowanie, gdy wiesz, że nie zakleszcza.

Czy ktoś mógłby pomóc mi dowiedzieć się, jak nie używać buforowanego kanału dla tego? Czy to możliwe?

Ponadto zrobiłem kilka badań nad tym, co dokładnie powoduje zakleszczenie.

Jakiś cytat jak z https://stackoverflow.com/a/18660709/921082,

Jeśli kanał jest nieufny, blokuje nadawcy, dopóki odbiornik otrzymał wartość. Jeśli kanał ma bufor, bloków nadawcy tylko do momentu skopiowania wartości do bufora; Jeśli bufor jest pełny, oznacza to oczekiwanie, aż niektóre odbiornik pobrał wartość.

Powiedział inaczej:

  1. Gdy kanał jest pełny, nadawca czeka na kolejną gutorinę jakiś pokój, otrzymując

  2. Możesz zobaczyć nieufny kanał jako zawsze pełny: Musi być kolejna gnouta, aby wziąć na to, co wysyła nadawca.

Więc w mojej oryginalnej sytuacji, co prawdopodobnie powoduje, że zakleszczenie jest może:

  1. Zakres na kanale nie otrzymuje?

  2. Zakres na kanale nie otrzymuje oddzielonej procedury. ?

  3. oneResult nie jest odpowiednio zamknięty, więc zakres na kanale nie wie, gdzie jest koniec?

Dla numeru 3, nie wiem, czy jest coś złego o zamknięciu oneResult przed przedziałem, ponieważ ten wzór pojawia się na wielu przykładach w Internecie. Jeśli jest to numer 3, czy to może być coś złego w grupie czekania?

Mam inny artykuł bardzo podobny do mojej sytuacji HTTPS: // Robertbasic. COM / BLOG / Buffered-vs-nieustannie-kanały-w-golang /, w jego Druga lekcja dowiedziała się, używa nieskończonej pętli for { select {} } jako alternatywę do przedziału, wydaje się rozwiązać jego problem.

 go func() {
        for{
            select {
            case p := <-pch:
                findcp(p)
            }
        }
    }()

Lekcja Numer 2 - Niestażenie kanał nie może utrzymać wartości (YAH, to właśnie w nazwie "niestrunie"), więc cokolwiek zostanie wysłane do tego kanału, należy go odebrać przez jakiś inny kod. Który przyjmujący kod musi znajdować się w innej moutine, ponieważ jedna Gooutine nie może robić dwóch rzeczy w tym samym czasie: nie może wysłać i otrzymywać; To musi być jedna lub druga.

Dzięki

go
4
tomriddle_1234 26 luty 2019, 17:15

2 odpowiedzi

Najlepsza odpowiedź

Zakleszczenie nie jest w pętli przeciążenia. Jeśli uruchomisz kod na Plac zabaw zobaczysz w górnej części Stacktrace Błąd jest spowodowany przez wg2.Wait (linia 88 na placu zabaw i wskazywana przez Stacktrace). Również w StackTrace można zobaczyć wszystkie godziny, które nie skończyły z powodu impasu, jest to dlatego, że oneResult<-t nigdy nie kończy, więc żadna z gorynów rozpoczął się w pętli kiedykolwiek skończył.

Głównym problemem jest tutaj:

wg2.Wait()
close(oneResult)

// ...

for n := range oneResult{
// ...

Zapętlą się również przez zamknięty kanał nie jest tym, czego chcesz, zakładam. Jednak nawet jeśli nie zamknąłeś kanału, pętla nigdy nie zacznie się, ponieważ wg2.Wait() będzie czekać, aż zrobiono .

oneResult <- t
wg2.Done()

Ale nigdy się nie skończy, ponieważ opiera się na pętli, która już działa. Linia oneResult <- t nie zostanie zakończona, chyba że jest ktoś po drugiej stronie odbiór z tego kanału, który jest pętli, jednak ta pętla przewyższa przeciążeniowa nadal czeka na zakończenie wg2.Wait().

Zasadniczo masz "zależność kołową" między nadawcą i odbiornikiem kanału.

Aby naprawić problem, musisz zezwolić, aby pętla rozpoczęła odbierać od kanału, jednocześnie upewniając się, że kanał jest zamknięty po zakończeniu. Możesz robić coś, owijając dwie linie oczekiwania i bliskie do własnej goryn.

https://play.golang.com/p/rwwcfvszz6q.

2
mkopriva 26 luty 2019, 16:55

Musisz dodać bufor do zmiennej {x0}}

enter image description here

Objaśnienie: https://www.rapidloop.com/blog/golang- Kanały-Tips-Tricks.html

1
Jessé Catrinck 26 luty 2019, 14:28