Um Tutorial para a Linguagem de Programação Go – parte 9

Posted by ALOVasconcelos on Dec 10, 2009 in Dicas, Tutoriais, laboratório |

Multiplexação

[Voltar ao menu]

Multiplexação

Com channels, é possível servir múltiplos clientes goroutines independentes sem escrever
um multiplexador explícito. O truque é enviar ao servidor um channel na mensagem,
o quel será então usado para responder ao sender original.

Um programa cliente-servidor real tem muito código, então aqui está um substituto bastante
simples para ilustrar a idéia. Ele começa definindo um tipo “request”, que embute um channel
que será usado para responder.

    type request struct {
        a, b    int;
        replyc  chan int;
    }

O servidor será trivial: ele fará operações simples com inteiros. Aqui está o código
que invoca a operação e responde à requisição:

    type binOp func(a, b int) int

    func run(op binOp, req *request) {
        reply := op(req.a, req.b);
        req.replyc <- reply;
    }

A linha 18 define o nome "binOp" para a função recebendo dois inteiros e
retornando um terceiro.

A rotina "server" executa um loop infinito, recebendo requisições e, para prevenir
bloqueio devido a operações muito demoradas, "starta" uma goroutine para fazer o trabalho de verdade.

    func server(op binOp, service chan *request) {
        for {
            req := <-service;
            go run(op, req);  // Não espera
        }
    }

Construimos um servidor de uma forma familiar, "startando-o" e retornando um channel
conectado a ele:

    func startServer(op binOp) chan *request {
        req := make(chan *request);
        go server(op, req);
        return req;
    }

Aqui está um teste simples. Ele "starta" um servidor com um operador de adição e
envia N requisições sem esperar por suas respostas. Apenas depois de que todas as
requisições enviadas sejam executadas, checa seus resultados.

    func main() {
        adder := startServer(func(a, b int) int { return a + b });
        const N = 100;
        var reqs [N]request;
        for i := 0; i < N; i++ {
            req := &reqs[i];
            req.a = i;
            req.b = i + N;
            req.replyc = make(chan int);
            adder <- req;
        }
        for i := N-1; i >= 0; i-- {   // Não importa a ordem
            if <-reqs[i].replyc != N + 2*i {
                fmt.Println("fail at", i);
            }
        }
        fmt.Println("done");
    }

Um contra-tempo com este programa é que ele não desliga o servidor de forma limpa; quando "main" retorna
existe um número de goroutines prolongadas bloqueadas na comunicação. Para resolver isto, podemos
prover um segundo channel "quit" para o servidor:

    func startServer(op binOp) (service chan *request, quit chan bool) {
        service = make(chan *request);
        quit = make(chan bool);
        go server(op, service, quit);
        return service, quit;
    }

Ele passa o channel quit para a função "server", que o utiliza desta forma:

    func server(op binOp, service chan *request, quit chan bool) {
        for {
            select {
            case req := <-service:
                go run(op, req);  // Não espera
            case <-quit:
                return;
            }
        }
    }

Dentro da função "server", a declaração "select" escolhe qual das múltiplas comunicações
listadas pelos seus "cases" pode continuar. Se todos estiverem bloqueados, aguarda até que um
possa continuar; se vários puderem prosseguir, escolhe um aleatoriamente. Neste exemplo, o
"select" permite ao servidor reconhecer requisições até que receba a mensagem "quit", no ponto
em que retorna, terminando sua execução.

Tudo que resta é focalizar o channel "quit" no fim de main:

        adder, quit := startServer(func(a, b int) int { return a + b });
        quit <- true;

Existe muito mais sobre programação Go e programação concorrente em geral, mas este "quick tour"
deve lhe oferecer alguns dos princípios básicos.

Bom, esta foi a última parte da minha tradução do Tutorial disponibilizado pela equipe do Go.
Meu inglês anda meio enferrujado, então se alguém puder contribuir sugerindo alterações
no texto, agradeço.

Um forte abraço a todos.

\\//

yIn nI' yISIQ 'ej yIchep

André Luiz de Oliveira Vasconcelos

Tags: , , ,

2 Comments

Leave a Reply

XHTML: You can use these tags:' <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Copyright © 2008-2010 ALOVasconcelos All rights reserved.
Desk Mess Mirrored v1.5.1 theme from BuyNowShop.com.