haskell concorrente - mcta016-13 - paradigmas de...
TRANSCRIPT
![Page 1: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/1.jpg)
Haskell ConcorrenteMCTA016-13 - Paradigmas de Programação
Emilio [email protected]
Centro de Matemática, Computação e CogniçãoUniversidade Federal do ABC
![Page 2: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/2.jpg)
Disclaimer
■ Estes slides foram preparados para o curso de Paradigmasde Programação na UFABC.
■ Este material pode ser usado livremente desde que sejammantidos, além deste aviso, os créditos aos autores einstituições.
■ Conteúdo baseado no texto preparado, e gentilmentecedido, pelo Professor Fabrício Olivetti de França daUFABC.
1
![Page 3: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/3.jpg)
Haskell Concorrente
![Page 4: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/4.jpg)
Programação Concorrente
O objetivo da programação concorrente é definirexplicitamente múltiplos caminhos de controle, geralmentepara permitir múltiplas interações com usuário ou interfacesexternas.
Não necessariamente serão executadas em paralelo.
2
![Page 5: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/5.jpg)
Programação Concorrente
A ideia é descrever cada interação em separado, mas fazercom que elas ocorram ao mesmo tempo (intercaladamente).
3
![Page 6: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/6.jpg)
Programação Concorrente
Considere um Web Browser que permite carregar múltiplaspáginas ao mesmo tempo.
Além disso, enquanto ele carrega uma ou mais páginas, ainterface ainda interage com o usuário (apertar o botãocancelar, etc.)
4
![Page 7: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/7.jpg)
Programação Concorrente
Um servidor Web também implementa concorrência paraservir múltiplos pedidos ao mesmo tempo.
Imagine a situação de um servidor Web atendendo um pedidode página por vez.
5
![Page 8: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/8.jpg)
Haskell Concorrente
O Haskell fornece um conjunto de funcionalidades simplesmas genéricas que podem ser utilizadas para definir estruturasmais complexas.
Com isso fica a cargo do programador definir o melhor modelode programação concorrente.
6
![Page 9: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/9.jpg)
Conceitos Básicos
![Page 10: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/10.jpg)
Criando uma thread
Uma thread é a menor sequência de computação que pode sergerenciada de forma independente pelo gerenciador detarefas.
Um processo é um procedimento computacional completo quepode conter diversas threads de execução.
7
![Page 11: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/11.jpg)
Criando uma thread
Múltiplas threads de um mesmo processo compartilham amemória alocada, podendo utilizá-la para troca de mensagens.
Múltiplos processos não compartilham memória alocada.
8
![Page 12: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/12.jpg)
Criando uma thread
No Haskell criamos uma thread com a função forkIO:
1 import Control.Concurrent2
3 forkIO :: IO () -> IO ThreadId
Ela recebe uma ação computacional de IO como argumento eretorna um identificador dessa thread.
9
![Page 13: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/13.jpg)
Criando uma thread
A ideia é que todo efeito colateral feito pela ação IO será feitode forma concorrente com outras threads:
1 import Control.Concurrent2 import Control.Monad3 import System.IO4
5 main = do6 hSetBuffering stdout NoBuffering7 forkIO (replicateM_ 100000 (putChar 'A'))8 replicateM_ 100000 (putChar 'B')
10
![Page 14: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/14.jpg)
Criando uma thread
A primeira linha da função main desativa o buffer paraexecutar toda ação IO no momento exato em que ela éenviada.
1 import Control.Concurrent2 import Control.Monad3 import System.IO4
5 main = do6 hSetBuffering stdout NoBuffering7 forkIO (replicateM_ 100000 (putChar 'A'))8 replicateM_ 100000 (putChar 'B')
11
![Page 15: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/15.jpg)
Criando uma thread
A segunda linha cria uma thread que imprimirá o caractere Adez mil vezes.
1 import Control.Concurrent2 import Control.Monad3 import System.IO4
5 main = do6 hSetBuffering stdout NoBuffering7 forkIO (replicateM_ 100000 (putChar 'A'))8 replicateM_ 100000 (putChar 'B')
12
![Page 16: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/16.jpg)
Criando uma thread
A terceira linha imprime o caractere B dez mil vezes.
1 import Control.Concurrent2 import Control.Monad3 import System.IO4
5 main = do6 hSetBuffering stdout NoBuffering7 forkIO (replicateM_ 100000 (putChar 'A'))8 replicateM_ 100000 (putChar 'B')
13
![Page 17: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/17.jpg)
Criando uma thread
A execução do programa resultará em caracteres A e Bintercalados:
AAAAAAAAABABABABABABABABABABABABAABABABABAB…
14
![Page 18: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/18.jpg)
Exemplo 1: Lembretes
Vamos criar uma função multithread que aguarda o usuárioentrar com um tempo em segundos e cria uma thread paraimprimir uma mensagem após esse número de segundostenha passado:
1 import Control.Concurrent2 import Control.Monad3
4 main = forever $ do5 s <- getLine6 forkIO $ setReminder s
15
![Page 19: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/19.jpg)
Exemplo 1: Lembretes
A função forever está definida na bibliotecaControl.Monad e simplesmente repete a ação eternamente.A função setReminder pode ser definida como:
1 setReminder :: String -> IO ()2 setReminder s = do3 let t = read s :: Int4 putStrLn ("Ok, adicionado para " ++ show t ++ "
segs.")↪→
5 threadDelay (10^6 * t)6 putStrLn (show t ++ " segundos se passaram! BING!"
A função threadDelay suspende a execução da thread por nmicrosegundos.
16
![Page 20: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/20.jpg)
Exemplo 1: Lembretes
Exemplo de execução:
1 $ ./lembrete2 23 Ok, adicionado para 2 segs.4 45 Ok, adicionado para 4 segs.6 2 segundos se passaram! BING!7 4 segundos se passaram! BING!
17
![Page 21: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/21.jpg)
Exercício 01 (0.5 pto)
Altere o programa anterior para terminar o programa assimque o usuário digitar quit.
DICA: troque o uso de forever por uma função definida porvocê denominada repita.
18
![Page 22: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/22.jpg)
Resposta
1 main = repita2 where repita = do3 s <- getLine4 if s == "quit"5 then return ()6 else do forkIO $ setReminder s7 repita
19
![Page 23: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/23.jpg)
Comunicação entre threads: MVar
Para que as threads possam se comunicar entre si é necessárioa existência de um espaço de memória compartilhada.
No Haskell isso é implementado através do tipo MVar:
1 data MVar a2
3 newEmptyMVar :: IO (MVar a)4 newMVar :: a -> IO (MVar a)5 takeMVar :: MVar a -> IO a6 putMVar :: MVar a -> a -> IO ()
20
![Page 24: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/24.jpg)
MVar
O tipo MVar é um container para qualquer tipo de dado. Vocêpode armazenar um valor Integer, uma String, uma listade Bool, etc.A função newEmptyMVar cria um MVar inicialmente vazio. Afunção newMVar recebe um argumento x e retorna um MVarcontendo x.As funções takeMVar e putMVar, inserem e removem umconteúdo em um MVar.
21
![Page 25: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/25.jpg)
MVar
Notem que MVar armazena apenas um único valor em suaestrutura:
■ Se uma thread chamar takeMVar e ela estiver vazia,ficará bloqueada em espera até que algum conteúdo sejainserido.
■ Se uma thread chamar putMVar e ela estiver cheia, ficarábloqueada em espera até que alguema thread utilizetakeMVar.
22
![Page 26: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/26.jpg)
MVar
Considere o seguinte código exemplo:
1 main = do2 m <- newEmptyMVar3 forkIO $ do putMVar m 'x'; putMVar m 'y'4 r1 <- takeMVar m5 print r16 r2 <- takeMVar m7 print r2
23
![Page 27: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/27.jpg)
MVar
Inicialmente, cria-se uma MVar vazia:
1 main = do2 m <- newEmptyMVar3 forkIO $ do putMVar m 'x'; putMVar m 'y'4 r1 <- takeMVar m5 print r16 r2 <- takeMVar m7 print r2
24
![Page 28: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/28.jpg)
MVar
Em seguida, criamos uma thread que armazena dois caracteresna sequência, ao inserir o primeiro caractere a thread ficabloqueada aguardando espaço ser liberado.
1 main = do2 m <- newEmptyMVar3 forkIO $ do putMVar m 'x'; putMVar m 'y'4 r1 <- takeMVar m5 print r16 r2 <- takeMVar m7 print r2
25
![Page 29: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/29.jpg)
MVar
Nesse momento o thread principal recupera o valor de MVar earmazena em r1, liberando espaço para a thread armazenar osegundo caractere.
1 main = do2 m <- newEmptyMVar3 forkIO $ do putMVar m 'x'; putMVar m 'y'4 r1 <- takeMVar m5 print r16 r2 <- takeMVar m7 print r2
26
![Page 30: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/30.jpg)
MVar
Ao final, o segundo caractere é recuperado e MVar se tornavazio.
1 main = do2 m <- newEmptyMVar3 forkIO $ do putMVar m 'x'; putMVar m 'y'4 r1 <- takeMVar m5 print r16 r2 <- takeMVar m7 print r2
27
![Page 31: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/31.jpg)
Mecanismo anti-burrice
E se o programador escrever o seguinte programa:
1 main = do2 m <- newEmptyMVar3 takeMVar m
28
![Page 32: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/32.jpg)
Mecanismo anti-burrice
A execução retornará:
1 $ ./burro2 burro: thread blocked indefinitely in an MVar operation
Se você criar um programa em que a thread fica bloqueadaeternamente, em muitos casos o programa emite uma exceçãoBlockedIndefinitelyOnMVar.
29
![Page 33: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/33.jpg)
Construindo tipos mutáveis comMVar
![Page 34: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/34.jpg)
Tipos mutáveis
Como sabemos, os tipos do Haskell são imutáveis, ou seja, umavez que definimos uma variável ela não pode mudar de valor.
O tipo MVar pode nos ajudar a simular um tipo mutável apartir de um tipo imutável de forma transparente!
30
![Page 35: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/35.jpg)
Tipo Map
A biblioteca Data.Map fornece o tipo mapa associativo:
1 data Map k a2
3 import qualified Data.Map as M
que define um mapa associativo com chave do tipo k e valoresdo tipo a.
31
![Page 36: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/36.jpg)
Tipo Map
Essa biblioteca possui as funções:
1 M.empty :: Map k a2
3 M.insert :: Ord k => k -> a -> Map k a -> Map k a4 M.insert k v m = -- insere valor v na chave k do mapa m,5 -- substituindo caso já exista6
7 M.lookup :: Ord k => k -> Map k a -> Maybe a8 M.lookup k m = -- retorna o valor na chave k do mapa m,9 -- retorna Nothing caso não exista a chave
32
![Page 37: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/37.jpg)
Agenda telefônica
Vamos criar o tipo agenda telefônica:
1 type Nome = String2 type Numero = String3 type Agenda = M.Map Nome Numero
33
![Page 38: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/38.jpg)
Agenda telefônica
Mas uma agenda telefônica não pode ser uma estruturaimutável. Preciso ter a capacidade de inserir novos nomes eatualizar as entradas. Vamos definir uma agenda telefônicamutável como:
1 newtype AgendaMut = AgendaMut (MVar Agenda)
34
![Page 39: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/39.jpg)
Exercício (0.5 pto)
Defina a função novaAgenda que cria uma agenda mutávelvazia.
1 novaAgenda :: IO AgendaMut
35
![Page 40: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/40.jpg)
Resposta
1 novaAgenda :: IO AgendaMut2 novaAgenda = do m <- newMVar M.empty3 return (AgendaMut m)
36
![Page 41: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/41.jpg)
Exercício
Defina agora a função insere que insere um nome e umtelefone:
1 insere :: AgendaMut -> Nome -> Numero -> IO ()2 insere (AgendaMut m) nome numero = ??
37
![Page 42: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/42.jpg)
Resposta
1 insere :: AgendaMut -> Nome -> Numero -> IO ()2 insere (AgendaMut m) nome numero = do3 agenda <- takeMVar m4 putMVar m (M.insert nome numero agenda)
38
![Page 43: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/43.jpg)
Exercício
Defina a função procura que retorna uma entrada da agenda:
1 procura :: AgendaMut -> Nome -> IO (Maybe Numero)2 procura (AgendaMut m) -> Nome = do
39
![Page 44: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/44.jpg)
Resposta
1 procura :: AgendaMut -> Nome -> IO (Maybe Numero)2 procura (AgendaMut m) nome = do3 agenda <- takeMVar m4 putMVar m agenda -- guarda de volta5 return (M.lookup nome agenda)
40
![Page 45: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/45.jpg)
Agenda Mutável
Dessa forma, podemos trabalhar com a agenda da seguinteforma:
1 nomes = [("Joao", "111-222"), ("Maria", "222-111"),2 ("Marcos", "333-222")]3
4 main = do5 s <- novaAgenda6 mapM_ (uncurry (insere s)) nomes7 print =<< procura s "Marcos"8 print =<< procura s "Ana"
41
![Page 46: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/46.jpg)
Agenda Mutável
O operador =<< é igual ao operador >>= mas invertido.Converta a expressão:
1 print =<< procura s "Marcos"
para a notação do
42
![Page 47: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/47.jpg)
Resposta
1 do x <- procura s "Marcos"2 print x
43
![Page 48: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/48.jpg)
Agenda Mutável
Se essas funções forem utilizadas em um programa que criamúltiplas threads podemos observar algumas vantagens:
■ Durante a operação de busca não é necessário criar umlock no estado da agenda durante a operação.
■ Graças a avaliação preguiçosa, também não se faznecessário um lock por muito tempo no momento dainserção.
44
![Page 49: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/49.jpg)
Operações Assíncronas
![Page 50: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/50.jpg)
Operações Assíncronas
Imagine a situação em que desejamos capturar o conteúdo deuma lista de páginas da Web. Queremos fazer isso de formaconcorrente e, após o encerramento de todas as threads,quero aplicar alguma função nos resultados.
45
![Page 51: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/51.jpg)
Operações Assíncronas (1/3)
Nosso código seria algo como:
1 import Control.Concurrent2 import Data.ByteString as B3 import GetURL4
5 main = do6 m1 <- newEmptyMVar7 m2 <- newEmptyMVar
46
![Page 52: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/52.jpg)
Operações Assíncronas (2/3)
1 forkIO $ do2 r <- getURL "http://www.wikipedia.org/wiki/Shovel"3 putMVar m1 r4
5 forkIO $ do6 r <- getURL "http://www.wikipedia.org/wiki/Spade"7 putMVar m2 r
47
![Page 53: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/53.jpg)
Operações Assíncronas (3/3)
1 r1 <- takeMVar m12 r2 <- takeMVar m23 print (B.length r1, B.length r2)
48
![Page 54: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/54.jpg)
Operações Assíncronas
A ideia é que as duas threads façam o download do conteúdode cada URL em background assincronamente.
Uma operação assíncrona é uma operação que é feita embackground enquanto eu posso fazer outras operações quenão dependam dela, e permita que eu aguarde o final pararealizar alguma operação sobre os resultaos.
49
![Page 55: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/55.jpg)
Operações Assíncronas
O código está muito repetitivo. E se eu quiser fazer a mesmaoperação para uma lista de URLs? Vamos generalizar:
1 data Async a = Async (MVar a)
50
![Page 56: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/56.jpg)
Operações Assíncronas
1 async :: IO a -> IO (Async a)2 async action = do3 var <- newEmptyMVar4 forkIO (do r <- action; putMVar var r)5 return (Async var)
51
![Page 57: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/57.jpg)
Operações Assíncronas
1 wait :: Async a -> IO a2 wait (Async var) = readMVar var
Essas funções estão definidas na bibliotecaControl.Concurrent.Async
52
![Page 58: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/58.jpg)
Operações Assíncronas
A função async cria uma thread a ser executadaassíncronamente com outras.
A função wait aguarda o final da execução de uma threadassíncrona.
53
![Page 59: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/59.jpg)
Operações Assíncronas
Dessa forma nosso código pode ser reescrito como:
1 import Control.Concurrent2 import Data.ByteString as B3 import GetURL4
5 url1 = "http://www.wikipedia.org/wiki/Shovel"6 url2 = "http://www.wikipedia.org/wiki/Spade"7
8 main = do9 a1 <- async (getURL url1)
10 a2 <- async (getURL url2)11 r1 <- wait a112 r2 <- wait a213 print (B.length r1, B.length r2)
54
![Page 60: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/60.jpg)
Operações Assíncronas
Assim, podemos capturar uma lista de sites da seguinte forma:
1 main = do2 as <- mapM (async . getURL) sites3 rs <- mapM wait as4 mapM_ (r -> print $ B.length r) rs
55
![Page 61: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/61.jpg)
Tratamento de Erro
E se uma das URLs não existir ou retornar algum erro?Devemos jogar fora todos os resultados e exibir umamensagem de erro?
A biblioteca async define a função:
1 waitCatch :: Async a -> IO (Either SomeException a)
Que retorna ou um erro, que pode ser tratado, ou o valoresperado. Para tratar o erro devemos importar também importControl.Exception
56
![Page 62: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/62.jpg)
Either
O tipo Either é definido como:
1 data Either a b = Left a | Right b
e assim como o Maybe é utilizado para tratamento de erro. Elediz: ”ou vou retornar algo do tipo a ou do tipo b”, sendo o tipoa geralmente tratado como o erro.
57
![Page 63: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/63.jpg)
Tratamento de Erro
Então podemos definir:
1 printLen :: (Either SomeException B.ByteString) -> IO ()2 printLen (Left e) = print "URL not found"3 printLen (Right b) = print $ B.length b
58
![Page 64: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/64.jpg)
Tratamento de Erro
E então:
1 main = do2 as <- mapM (async . getURL) sites3 rs <- mapM waitCatch as4 mapM_ printLen rs
59
![Page 65: Haskell Concorrente - MCTA016-13 - Paradigmas de Programaçãoprofessor.ufabc.edu.br/~e.francesquini/2019.q2... · HaskellConcorrente MCTA016-13-ParadigmasdeProgramação EmilioFrancesquini](https://reader034.vdocuments.net/reader034/viewer/2022043006/5f9172bfef36b90cb51353c8/html5/thumbnails/65.jpg)
Leituras complementares
Com isso finalizamos o assunto de Programação Concorrentenessa disciplina, embora não tenhamos esgotado todos osconceitos.
Para quem quiser avançar no assunto, a leitura do livro doSimon Marlow é obrigatória!
60