четверг, 31 января 2019 г.

Эффективный Go: каналы каналов

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

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

type Request struct {
    args        []int
    f           func([]int) int
    resultChan  chan int
}

Клиент предоставляет функцию и ее аргументы, а также канал внутри объекта запроса, по которому можно получить ответ.

func sum(a []int) (s int) {
    for _, v := range a {
        s += v
    }
    return
}

request := &Request{[]int{3, 4, 5}, sum, make(chan int)}
// Отправляем запрос (request)
clientRequests <- request
// Ждем ответ
fmt.Printf("answer: %d\n", <-request.resultChan)

На стороне сервера функция обработчика (handle function) - единственное, что изменяется.

func handle(queue chan *Request) {
    for req := range queue {
        req.resultChan <- req.f(req.args)
    }
}

Очевидно, что еще многое предстоит сделать, чтобы сделать этот пример реалистичным, но этот код является основой для параллельной неблокирующей RPC системы с ограниченной скоростью пропуска сообщений, и здесь нет и следа мьютекса.


Читайте также:


Комментариев нет:

Отправить комментарий