Практика параллельного программирования Golang | Go Theme Month

Go
Практика параллельного программирования Golang | Go Theme Month

Люди — высококонкурентный вид, деликатный.

первое знакомство

Первое впечатление от языка Go состоит в том, что он изначально поддерживает параллельное программирование и использует сопрограммы, которые легче, чем потоки.

ybk93cwmg3y51.jpg

Разница между процессами, потоками и сопрограммами

  • Процесс — это «экземпляр выполнения программы», который действует как объект, распределяющий системные ресурсы. Создание процесса должно выделять полное отдельное адресное пространство. Переключение процессов происходит только в режиме ядра.
  • Поток: Поток — это поток выполнения процесса, который независимо выполняет свой собственный программный код.Это наименьшая единица потока выполнения программы и основная единица планирования и диспетчеризации процессора. Процесс может иметь один или несколько потоков.
  • Сопрограммы: сопрограммы не являются процессами или потоками, и их выполнение больше похоже на подпрограмму или вызов функции без возвращаемого значения. Параллельные сопрограммы могут быть созданы на уровне языка, а затем написаны для управления ими. Go отдает этот шаг на аутсорсинг, чтобы сделать параллельный запуск сопрограмм менее затратным.

a.jpeg

Go реализует простейший параллелизм

for i := 0; i < 10; i++ {
    go func(n int) {
        fmt.Println(n)
    }(i)
}

Проектная практика

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

Выполнять задание последовательно

Изначально у нас есть метод, который выполняет задание и выполняет все задания последовательно:

func buildJob(name string) {
    ...
}

buildJob("A")
buildJob("B")
buildJob("C")

Выполнять задания параллельно

Поскольку все задания могут выполняться одновременно, нет необходимости ждать завершения выполнения предыдущего задания, прежде чем продолжить выполнение других заданий. Мы можем использовать ключевые слова языка Gogoчтобы быстро включитьgoroutine, ниже мы будем выполнять три задания одновременно:

go buildJob("A")
go buildJob("B")
go buildJob("C")

дождитесь завершения всех заданий

Как я могу узнать, было ли выполнено каждое задание, здесь вы можете использоватьchannelобщаться и использоватьselectПроверяем результат выполнения:

func buildJob(ch chan error, name string) {
    var err error
    
    ... // build job
    
    ch <- err // finnaly, send the result into channel
}

func build() error {
    jobCount := 3
    errCh := make(err chan error, jobCount)
    defer close(errCh) // 关闭 channel

    go buildJob(errCh, "A")
    go buildJob(errCh, "B")
    go buildJob(errCh, "C")

    for {
        select {
        case err := <-ch:
            if err != nil {
                return err
            }
        }
        
        jobCount--
        if jobCount <= 0 {
            break
        }
    }
    
    return nil
}

проблема найдена

Когда задание А не выполняется,buildметод будетreturn errвыйти и выполнитьclose(errCh). Однако в это время другие два задания B и C могут быть не завершены, и результаты также будут отправлены вerrCh, но с этого времениerrChбыл закрыт, что приведет к выходу программыpanic: send on closed channel.

оптимизировать код

При отправке данных в канал вы можете использовать второе значение полученных данных, чтобы определить, закрыт ли канал:

func buildJob(ch chan error, name string) {
    var err error
    
    ... // build job
    
    if _, ok := <-ch; !ok {
        return
    }
    ch <- err // finnaly, send the result into channel
}

func build() error {
    jobCount := 3
    errCh := make(err chan error, jobCount)
    defer close(errCh) // 关闭 channel

    go buildJob(errCh, "A")
    go buildJob(errCh, "B")
    go buildJob(errCh, "C")

    for {
        select {
        case err := <-ch:
            if err != nil {
                return err
            }
        }
        
        jobCount--
        if jobCount <= 0 {
            break
        }
    }
    
    return nil
}

Суммировать

Параллельное программирование Go, кажется, нуждается только в одном ключевом словеgoможно бежатьgoroutine, но на практике все же есть проблемы, с которыми нужно разобраться.

Оригинальная ссылка:Доступно на 8scat.com/posts/code-…