Неожиданный результат при сортировке цифр с помощью Goroutines - PullRequest
0 голосов
/ 11 апреля 2020

Я выполняю некоторые упражнения в Go, и у меня странное поведение с моим кодом. Если бы кто-то мог объяснить мне причину, это могло бы быть действительно здорово.

Вот код: https://play.golang.org/p/4fQYHWpD6Cj

package main

import (
    "fmt"
    "sort"
    "strconv"
)

func sortList (list []int, c chan []int) {
    sort.Ints(list)
    c <- list
}

func convert(sStr []string) (sInt []int){
cnvLoop: for _, r := range sStr {
    digit, err := strconv.Atoi(r)
    if err != nil {
        break cnvLoop
    }
    sInt = append(sInt, digit)
}
    return sInt
}

func split(list []int, size int) (tmpS []int, splS[]int) {
    tmpS = list[size:]
    splS = list[:size]
    return tmpS, splS
}

func main() {

    list := []string{"-9", "-11", "12", "13", "9"}
    fmt.Println("Your unsorted digits: ", list)
    sInt := convert(list)
    size := len(sInt) / 4


    tmpS, splS1 := split(sInt, size)
    tmpS, splS2 := split(tmpS, size)
    tmpS, splS3 := split(tmpS, size)
    splS4 := tmpS

    // sort in different go routines
    c := make(chan []int)
    go sortList(splS1, c)
    go sortList(splS2, c)
    go sortList(splS3, c)
    go sortList(splS4, c)

    // receive from a channel
    sortedS1 := <-c
    sortedS2 := <-c
    sortedS3 := <-c
    sortedS4 := <-c

    // merge the 4 sorted slices
    var sortedList1, sortedList2 []int
    sortedList1 = append(sortedS1, sortedS2...)
    sortedList2 = append(sortedS3, sortedS4...)
    finalList := append(sortedList1, sortedList2...)

    // we need to sort it again
    sort.Ints(finalList)
    fmt.Println("Here your digits sorted: ", finalList)
}

Теперь, если вы собираетесь проверить код на Goplayground будет работать каждый раз, но если вы запустите его на своем компьютере, результаты могут иногда откладываться. (пробовал GoLand на Windows и vim- go на Ubuntu)

Цель этого упражнения - просто ввести числа на срезе, вырезать этот срез на четыре части и отсортировать их, используя go подпрограммы, а затем объединить их в один отсортированный фрагмент.

Цель этого упражнения совершенно глупа, поскольку мне все равно придется сортировать большой фрагмент в конце, поэтому, пожалуйста, отложите цель в сторону и мой алгоритм, так как мы может сильно упростить.

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

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

На самом деле, ваша проблема не имеет никакого отношения к каналам, она связана с использованием массива / слайса. Вы используете срезы повсеместно, поэтому изначально существует только одна копия данных - sort.Ints() выполняет операции на месте, а канал также работает с срезами. Это означает, что до тех пор, пока вы append, в памяти будет только один массив.

И теперь append выполняет свою работу. Вот ключевая информация из документации:

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

В соответствии с этим, если емкость среза достаточна, append добавляет элементы в существующий массив (перераспределение отсутствует) и перезаписывает предыдущие данные. Таким образом, неисправная часть вашего кода является частью консолидации.

0 голосов
/ 12 апреля 2020

Хорошо, я понял, но когда я печатаю срез после добавления l oop, результаты добавления l oop каждый раз корректны, а окончательный отсортированный результат неверен. Помимо того, что я взял оба кода (неправильный и правильный), я расположил их так, чтобы они выглядели одинаково, и у меня все еще разный результат, единственное отличие состоит в том, что неправильный код полностью преобразуется в int и объединяется в 4 в исправьте один, они сначала сращены до 4, а затем преобразованы. Я могу представить, что добавление во втором решении сделано на маленьких кусочках, но все же. Я все еще в замешательстве, я все еще думаю, что есть какая-то проблема состояния гонки Пожалуйста, взгляните еще раз на эти два:

1- https://play.golang.org/p/-vOseYE1XLt

package main

import (
    "fmt"
    "sort"
    "strconv"
)

func send(slice []int, c chan []int) {
    sort.Ints(slice)
    c <- slice
}

// Split strings.
func split(list []string) (tmpS []string, splS []string) {
    tmpS = list[len(list)/2:]
    splS = list[0 : len(list)/2]
    return tmpS, splS
}

func convert(sStr []string) (sInt []int) {
    for _, r := range sStr {
        digit, _ := strconv.Atoi(r)
        sInt = append(sInt, digit)
    }
    fmt.Println("Sorted sub array: ", sInt)
    return sInt
}

func main() {
    list := []string{"-9", "-11", "12", "13", "9"}
    fmt.Println("Your unsorted digits: ", list)

    splS1, splS2 := split(list)
    splS11, splS12 := split(splS1)
    splS21, splS22 := split(splS2)

    // Convert each slices.
    sInt1 := convert(splS11)
    sInt2 := convert(splS12)
    sInt3 := convert(splS21)
    sInt4 := convert(splS22)

    // Send in different go routines.
    c := make(chan []int)
    go send(sInt1, c)
    go send(sInt2, c)
    go send(sInt3, c)
    go send(sInt4, c)

    // Receive from a channel.
    sortedS1 := <-c
    sortedS2 := <-c
    sortedS3 := <-c
    sortedS4 := <-c

    // Merge the 4 sorted slices.
    sortedList1 := append(sortedS1, sortedS2...)
    sortedList2 := append(sortedS3, sortedS4...)
    finalList := append(sortedList1, sortedList2...)

    // Sort it again
    sort.Ints(finalList)
    fmt.Println("Here your digits sorted: ", finalList)
}

2 - https://play.golang.org/p/L8WcrlTOVxZ

package main

import (
    "fmt"
    "sort"
    "strconv"
)

func send(list []int, c chan []int) {
    sort.Ints(list)
    c <- list
}

// Split integers.
func split(list []int) (tmpS []int, splS []int) {
    tmpS = list[len(list)/2:]
    splS = list[0 : len(list)/2]
    return tmpS, splS
}

func convert(sStr []string) (sInt []int) {
    for _, r := range sStr {
        digit, _ := strconv.Atoi(r)
        sInt = append(sInt, digit)
    }
    fmt.Println("Sorted sub array: ", sInt)
    return sInt
}

func main() {
    list := []string{"-9", "-11", "12", "13", "9"}
    fmt.Println("Your unsorted digits: ", list)

    // Convert the whole slice
    sInt := convert(list)

    splS1, splS2 := split(sInt)
    splS11, splS12 := split(splS1)
    splS21, splS22 := split(splS2)

    // Send in different go routines.
    c := make(chan []int)
    go send(splS11, c)
    go send(splS12, c)
    go send(splS21, c)
    go send(splS22, c)

    // Receive from a channel.
    sortedS1 := <-c
    sortedS2 := <-c
    sortedS3 := <-c
    sortedS4 := <-c

    // Merge the 4 sorted slices.
    sortedList1 := append(sortedS1, sortedS2...)
    sortedList2 := append(sortedS3, sortedS4...)
    finalList := append(sortedList1, sortedList2...)

    // Sort it again
    sort.Ints(finalList)
    fmt.Println("Here your digits sorted: ", finalList)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...