390 likes | 503 Views
Pós-Graduação em Modelagem Computacional – PGMC. Introdução a Computação Paralela Google Go Professor: Ricardo Fabbri Aluno: Mateus Guida Nova Friburgo, 01 de novembro de 2012. INTRODUÇÃO CONCEITOS E CARACTERÍSTICAS DESCRIÇÃO DA LINGUAGEM EXEMPLOS DO USO DO GOOGLE GO.
E N D
Pós-Graduação em Modelagem Computacional – PGMC Introdução a Computação Paralela Google Go Professor: Ricardo Fabbri Aluno: Mateus Guida Nova Friburgo, 01 de novembro de 2012.
INTRODUÇÃO CONCEITOS E CARACTERÍSTICAS DESCRIÇÃO DA LINGUAGEM EXEMPLOS DO USO DO GOOGLE GO ESTRUTURAÇÃO DA APRESENTAÇÃO
INTRODUÇÃO - Go é uma linguagem de programação criada pela Google e lançada em código livre em novembro de 2009. - É uma linguagem com programação concorrente, com recursos de multithreading e garbage collector. - Alinguagem possui características de sintaxe e performance semelhante às linguagens C/C++ e o dinamismo do Python. - O projeto inicial da linguagem foi feito em setembro de 2007 por Robert Griesemer, Rob Pike e Ken Thompson. - Atualmente, há implementações para Windows, Linux, Mac OS X e FreeBSD.
INTRODUÇÃO - A sintaxe de Go é semelhante a C, mas com a facilidade de uma linguagem dinâmica. - Linguagem segura: sem erros de tipo (problemas entre diferentes tipos de dados) e sem erros de memória (overflow, ponteiros que não apontam para objetos válidos). - Bom suporte para concorrência e comunicação (usando CSP). - Eficiente, garbagecollector - sem latência. - Alta velocidade de compilação.
CONCEITOS E CARACTERÍSTICAS Programação Concorrente - Execução simultânea de várias tarefas computacionais interativas, (programas separados ou como um conjunto de threads criadas por um único programa). - Executadas por um único processador, vários processadores em um único equipamento ou processadores distribuídos por uma rede. - Programação concorrente é relacionada com programação paralela, mas foca mais na interação entre as tarefas. - Comunicação por memória compartilhada ou por troca de mensagens.
CONCEITOS E CARACTERÍSTICAS Coordenando o acesso aos recursos - Exemplo bool saque( int quantia ) { if( balanco > quantia ) { balanco = balanco - quantia; return true; } else { return false; } } - balanco = 500; saque(300) e saque(350)
CONCEITOS E CARACTERÍSTICAS bool saque( int quantia ) { pthread_mutex_lock(v_bloqueio); if( balanco > quantia ) { balanco = balanco - quantia; pthread_mutex_unlock(v_bloqueio); return true; } else { pthread_mutex_unlock(v_bloqueio); return false; } }
CONCEITOS E CARACTERÍSTICAS Garbage Collector - Garbage Collector (ou GC, ou Coletor de Lixo) é um processo usado para a automação do gerenciamento de memória.. - Recupera uma área de memória inutilizada por um programa. - Contraponto: gerenciamento manual de memória - programador especifica as desalocações de memória.
CONCEITOS E CARACTERÍSTICAS • Vantagens: • programador não precisa se preocupar com o gerenciamento (desalocação as vezes até proibida); • evita erros de má utilização de ponteiros. • Desvantagens: • Consomem recursos computacionais para o gerenciamento; • omomento em que o objeto é realmente desalocado não é determinístico; • o uso de recursividade atrasa a desalocação automática, aumentando os requisitos de memória do algoritmo; • a detecção semântica de objetos a serem desalocados é um • problema indecidível para qualquer processo automático.
CONCEITOS E CARACTERÍSTICAS CPS - Communication Sequential Processes - Linguagem formal desenvolvida por Tony Hoare, também criador do Quicksort e da Lógica de Hoare. - Permite a descrição de sistemas em termos de processos de componentes, que operam de forma independente e interagem atráves de troca de mensagens. - A forma como cada processo se comunica com o seu ambiente é usando vários operadores algébricos.
CONCEITOS E CARACTERÍSTICAS • Composta por: • Eventos (canais) • Processos (equações) • Operadores sobre processos e/ou eventos • Estrutura de dados baseadas no paradigma funcional • Álgebra de Processos. • - Cada processo possui seu próprio estado e comunicam-se com os outros. • - A comunicação acontece através dos eventos, que são atômicos. Só ocorre através da sincronização entre dois ou mais processos.
CONCEITOS E CARACTERÍSTICAS • STOP e SKIP. • Prefixo ( -> ): comportamento linear • Ex: ev-> Proc • Ex: TwoSteps = leftFoot -> rightFoot -> SKIP • Escolha Determinística ( [ ] ): possibilidade de P tanto quanto Q • A decisão não pertence a P[ ]Q, mas de quem interage com ele. • Escolha Não Determinística ( |~| ): se P e Q tem eventos iniciais em comum (a = b) • A escolha é feita pelo processo, internamente.
CONCEITOS E CARACTERÍSTICAS • Composição Paralela Síncrona ( || ): execução em paralelo, sincronizando todos os eventos em comum. • Ex: P || Q • Entrelaçamento( ||| ): execução em paralelo, de forma independente, sem sincronizar eventos. • Ex: P ||| Q • Composição Paralela Generalizada ( [|ev|] ) • * P [|x|] Q – P e Q são executados em paralelo, mas só sincronizando os eventos em x. Outros eventos são realizados de forma independente. • Ocultação ( \ ) • Ex: P\X - P\X comporta-se como P, exceto pelo fato de que os eventos em X são escondidos, executados internamente.
DESCRIÇÃO DA LINGUAGEM • Sintaxe semelhante a C. • blocos de código cercados por chaves - {} • estruturas de repetição e condicionais - for, switch, if. • Algumas diferenças • delimitação de linhas com ponto e vírgula são opcionais. • declaração de variáveis e tipos são diferenciadas. • novas palavras-chave de controle - go e select - para dar suporte a programação concorrente. • Ausência de parênteses em volta das estruturas for e if. • Vetores associativos e strings fazem parte da linguagem.
DESCRIÇÃO DA LINGUAGEM • Algumas funcionalidades ausentes são tratamento de exceção, herança, programação genérica, assert e sobrecarga de métodos. • Os autores expressam abertura para discutir programação genérica, mas argumentam abertamente contra asserções e defendem a omissão de herança de tipos em favor da eficiência. • Go é projetado para uma compilação rápida, mesmo em hardware modesto.
DESCRIÇÃO DA LINGUAGEM • Cada programa Go é composto de pacotes. • Programas começam rodando pelo pacote main. • O programa abaixo está usando os pacotes com caminhos de importação “fmt” e “math”. • Por convenção, o nome do pacote é o mesmo que o último elemento do caminho de importação. package main import ( "fmt" "math" ) func main() { fmt.Println("Dia", math.Pi, "Feliz") } Executando... Dia 3.141592653589793 Feliz
DESCRIÇÃO DA LINGUAGEM • Concorrência • Goroutines - Uma goroutine é um thread leve e gerenciado pelo runtime de Go. Ex: go f(x, y, z) • Goroutines executam no mesmo espaço de endereço, para que o acesso à memória compartilhada seja sincronizada. • Canais - Canais são um condutor tipado através do qual você pode enviar e receber valores com o operador de canal, <-. • Os canais devem ser criados antes de se usar - Ex: ch := make(chan int) • Por padrão, enviam e recebem um bloqueio até o outro lado estar pronto, permitindo que goroutines sincronizem sem bloqueios explícitos ou variáveis de condição. ch <- v // v envia para o canal ch. v := <-ch // Recebe do ch, e atribui o valor de v
DESCRIÇÃO DA LINGUAGEM package main import "fmt" func soma(a []int, c chan int) { soma := 0 for _, v := range a { soma += v } c <- soma // envia soma para c } func main() { a := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go soma(a[:len(a)/2], c) go soma(a[len(a)/2:], c) x, y := <-c, <-c // recebe de c fmt.Println(x, y, x + y) } Executando... 17 -5 12
DESCRIÇÃO DA LINGUAGEM • Os canais podem ser bufferizados. Fornecendo o tamanho do buffer como o segundo argumento para make para inicializar um canal bufferizado: • Enviar dados para um canal bufferizados bloqueia apenas quando o buffer está cheio. Receber dados bloqueia quando o buffer está vazio. ch := make(chan int, 100) package main import "fmt" func main() { c := make(chan int, 2) c <- 1 c <- 2 fmt.Println(<-c, <-c) } Executando... 1 2
DESCRIÇÃO DA LINGUAGEM package main import "fmt" func main() { c := make(chan int, 2) c <- 1 c <- 2 c <- 3 fmt.Println(<-c, <-c, <-c) } Executando... throw: all goroutines are asleep - deadlock! goroutine 1 [chan receive]: main.main() /tmpfs/gosandbox-a6ce82b3_746d45db_7e0da0f5_1870563c_a079aaeb/prog.go:7 +0x49 package main import "fmt" func main() { c := make(chan int, 2) fmt.Println(<-c, <-c) }
DESCRIÇÃO DA LINGUAGEM • Um remetente pode fechar um canal para indicar que os valores não serão mais enviados. Receptores podem testar se um canal foi fechado através da atribuição de um segundo parâmetro para a expressão de recepção: • oké false se não há mais valores a receber e o canal está fechado. • O laço for i := range c recebe valores do canal repetidamente até que seja fechado. • Nota: Apenas o remetente deve fechar um canal, nunca o receptor. O envio em um canal fechado irá causar um erro. • Outra nota: Canais não são como arquivos, você geralmente não precisa fechá-los. O encerramento só é necessário quando o receptor precisa saber que não há mais valores chegando, como para terminar um laço range. v, ok := <-ch
DESCRIÇÃO DA LINGUAGEM package main import ( "fmt" ) func fibonacci(n int, c chan int) { x, y := 1, 1 for i := 0; i < n; i++ { c <- x x, y = y, x + y } close(c) } func main() { c := make(chan int, 10) go fibonacci(cap(c), c) for i := range c { fmt.Println(i) } } Executando... 1 1 2 3 5 8 13 21 34 55
DESCRIÇÃO DA LINGUAGEM • A instrução select permite uma espera na goroutine sobre as operações de comunicação múltiplas. • O bloco select aguarda até que um de seus cases possam executar, então ele executa esse case. Ele escolhe um ao acaso se vários estiverem prontos. • O case default em um select é executado se nenhum outro caso está pronto.
DESCRIÇÃO DA LINGUAGEM • package main • import "fmt" • func fibonacci(c, quitchan int) { • x, y := 0, 1 • for { • select{ • case c <- x: • x, y = y, x + y • case <-quit: • fmt.Println("sair") • return • } • } • } • . • . • . • . • . • . • func main() { • c := make(chan int) • quit:= make(chan int) • go func() { • for i := 0; i < 10; i++ { • fmt.Println(<-c) • } • quit<- 0 • }() • fibonacci(c, quit) • }
DESCRIÇÃO DA LINGUAGEM Executando... 1 1 2 3 5 8 13 21 34 55 sair
DESCRIÇÃO DA LINGUAGEM package main import ( "fmt" "time" ) func main() { tick := time.Tick(1e8) boom := time.After(5e8) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(5e7) } } } Executando... . . tick. . . tick. . . tick. . . tick. . . tick. BOOM!
EXEMPLOS DO USO DO GOOGLE GO • Os exemplos aqui mostrados foram obtidos direto do Tour do Google Go, disponível online. • Os exemplos a seguir são exercícios propostos pelo Tour, que demonstram um pouco mais da simplicidade e praticidade da linguagem.
EXEMPLOS DO USO DO GOOGLE GO • Exemplo 1 - Árvores Binárias Equivalentes • Podem haver muitas árvores binárias diferentes com a mesma sequência de valores armazenados nas folhas. Por exemplo, aqui estão duas árvores binárias que armazenam a sequência 1, 1, 2, 3, 5, 8, 13.
EXEMPLOS DO USO DO GOOGLE GO • A função para verificar se duas árvores binárias armazenam a mesma seqüência é bastante complexa, na maioria das linguagens. Vamos usar a simultaneidade de Go e canais para escrever uma solução simples. • Este exemplo utiliza o pacote tree, o qual define o tipo: type Tree struct{ Left *Tree Value int Right *Tree }
EXEMPLOS DO USO DO GOOGLE GO package main import ( "fmt" "tour/tree" ) func Walk(t *tree.Tree, chchan int){ ift.Left != nil { Walk(t.Left, ch) } ch<-t.Value ift.Right != nil { Walk(t.Right, ch) } } . . . . . . func Same(t1, t2 *tree.Tree) bool { ch1:=make(chan int) ch2:=make(chan int) go Walk(t1, ch1) go Walk(t2, ch2) for i:=0; i<10; i++ { if <-ch1 != <-ch2 { return false } } return true } . . .
EXEMPLOS DO USO DO GOOGLE GO . . . func main() { ch := make(chan int) go Walk(tree.New(1), ch) for i:=0; i<10; i++ { fmt.Println(<-ch) } fmt.Println("Equivalent Binary Trees?", Same(tree.New(1), tree.New(1))) fmt.Println("Equivalent Binary Trees?", Same(tree.New(1), tree.New(2))) }
EXEMPLOS DO USO DO GOOGLE GO Executando... 1 2 3 4 5 6 7 8 9 10 Equivalent Binary Trees? true Equivalent Binary Trees? false
EXEMPLOS DO USO DO GOOGLE GO • Exemplo 2 - Webcrawler • Usaremos os recursos da concorrência de Go para paralelizar um web crawler., buscando URLs em paralelo, sem buscar a mesma URL duas vezes. • Um Web crawler é um tipo de robô de Internet ou agente de software. Em geral, ele começa com uma lista de URLs para visitar (também chamado de seeds). À medida que o crawler visita essas URLs, ele identifica todos os links na página e os adiciona na lista de URLs para visitar. Tais URLs são visitadas recursivamente de acordo com um conjunto de regras.
package main • import "fmt“ • type Fetcher interface { • Fetch(url string) (body string, urls []string, err error) • } • func Crawl(url string, depth int, fetcher Fetcher) { • type moreUrlsstruct{ • depth int • urls []string • } • more := make(chanmoreUrls) • getPage:= func(url string, depth int) { • body, urls, err := fetcher.Fetch(url) • iferr != nil { • fmt.Println(err) • } else{ • fmt.Printf("found[%d:%s] %q\n", depth, url, body) • } • more <- moreUrls{depth+1, urls} • } • . . .
. . . • outstanding:= 1 • go getPage(url, 0) • visited := map[string]bool{url:true} • for outstanding > 0 { • next := <-more • outstanding-- • ifnext.depth > depth { • continue • } • for _, url := range next.urls { • if _, seen := visited[url]; seen { • continue • } • visited[url] = true • outstanding++ • go getPage(url, next.depth) • } • } • } • . . .
. . . • func main() { • Crawl("http://golang.org/", 4, fetcher) • } • type fakeFetchermap[string]*fakeResult • type fakeResultstruct { • body string • urls []string • } • func (f *fakeFetcher) Fetch(url string) (string, []string, error) { • if res, ok := (*f)[url]; ok { • returnres.body, res.urls, nil • } • return "", nil, fmt.Errorf("não encontrado: %s",url) • } • . . .
. . . • var fetcher = &fakeFetcher{ • "http://golang.org/": &fakeResult{ • "The Go ProgrammingLanguage", • []string{ • "http://golang.org/pkg/", "http://golang.org/cmd/", • }, }, • "http://golang.org/pkg/": &fakeResult{ • "Packages", • []string{ • "http://golang.org/", "http://golang.org/cmd/", • "http://golang.org/pkg/fmt/", http://golang.org/pkg/os/", • }, }, • "http://golang.org/pkg/fmt/": &fakeResult{ • "Package fmt", • []string{ • "http://golang.org/", "http://golang.org/pkg/", • }, }, • "http://golang.org/pkg/os/": &fakeResult{ • "Package os", • []string{ • "http://golang.org/", "http://golang.org/pkg/", • }, }, • }
EXEMPLOS DO USO DO GOOGLE GO Executando... found[0:http://golang.org/] "The Go ProgrammingLanguage“ found[1:http://golang.org/pkg/] "Packages“ não encontrado: http://golang.org/cmd/ found[2:http://golang.org/pkg/fmt/] "Package fmt" found[2:http://golang.org/pkg/os/] "Package os"
http://golang.org • http://pt.wikipedia.org/wiki/Go_(linguagem_de_programa%C3%A7%C3%A3o) • http://en.wikipedia.org/wiki/Go_(programming_language) • http://www.devmedia.com.br/desmistificando-o-garbage-collector/5451 • http://www.guanabara.info/2009/11/google-lanca-linguagem-de-programacao-go/ • http://www.cin.ufpe.br/~if711/aulas/Aula%2002.pdf • http://go-tour-br.appspot.com/ BIBLIOGRAFIA