Slides Lição 5, CPAD, Os Inimigos do Cristão, 2Tr24, Pr Henrique.pptx
Modelo APM em .NET para programação assíncrona
1. Modelo APM em .NET
por
Pedro Gabriel
O porquê da utilização/necessidade de uma abordagem
assíncrona :
Esta necessidade surge devido, principalmente à evolução das arquitecturas que
passaram a ser multi-core em vez de single-core. Anteriormente, quando falávamos em
aplicações “escaláveis”, qualquer aplicação single-thread era escalável num ambiente
single-core, uma vez que todos os melhoramentos feitos aos processadores da época
eram baseados numa melhor performance em single-core.
Com o aparecimento de arquitecturas multi-core, qualquer aplicação single-thread
deixou de ser escalável, pois não tira partido das funcionalidades das novas
arquitecturas. Por suas vez, as linguagens de programação evoluiram de tal forma que
praticamente todas as linguagens de alto nível suportam este tipo de abordagem, dando
assim a possibilidade do programador criar aplicações multi-thread.
Principais diferenças entre “modelos”:
Normalmente, perante programas single-thread o fluxo de actividades pode ser
descrito da seguinte forma:
Estamos então, na presença de acções sequênciais, que mesmo sendo independentes ou
não, só serão executadas consoante a ordém disposta.
1
2. Modelo APM em .NET
por
Pedro Gabriel
No que toca a um programa multi-thread, podemos descrever o fluxo de acções da
seguinte forma:
Por esta ordem de ideias, cada acção é executada por uma Thread diferente, deixando
ao programador a gestão do fluxo do seu programa conforme o tempo que cada acção
pode levar a ser completada. Com esta abordagem, está implicito um overhead que
pode ser criado se uma aplicação tiver mais Threads do que processadores lógicos para
uma determinada máquina.
Tipicamente, estes custos podem ser descritos da seguinte forma:
● Custos Estáticos: Estão associados à memória utilizada para conter
estruturas de dados relativas às Threads, e ao espaço de endereçamento
alocado. Proporcional ao número de Threads.
● Custos Dinâmicos: Associados à actividade de scheduling. Quantas mais
Threads estiverem em execução - READY - maior será a actividade de
Scheduling. Proporcional ao número de Threads “Ready” para além do nº de
cores.
A este modelo está ainda adjacente a necessidade de implementar mecanismos de
sincronização de Threads relativamente ao acesso a dados, por forma a manter os
mesmos no estado correcto.
2
3. Modelo APM em .NET
por
Pedro Gabriel
Por último, resta demonstrar o fluxo de uma abordagem/modelo assíncrono.
Neste modelo, as ações são executadas de forma intercalada, com a gestão realizada
apenas por uma Thread.
Uma das grandes vantagens deste modelo, é o facto de o programador poder dar
“ordens” às ações a realizar. Do ponto de vista do segundo modelo (multi-thread), ações
podem ser interrompidas consoante o “desejo” do Sistema Operativo. Neste último
modelo é o programador quem pode dar ordem de interrupção, mantendo assim o
controlo sobre as ações.
3
4. Modelo APM em .NET
por
Pedro Gabriel
Após a descrição da motivação para o uso de programação assíncrona e uma breve
descrição dos modelos mais utilizados, vejamos agora um modelo concreto que foi o
principal padrão utilizado pela framework .NET antes da versão 4.5.
Este documento mostra ainda os três tipos de rendezvous que integram o APM:
Wait-Until Done, Polling, Callback.
Asynchronous Programming Model (APM):
Este padrão permite-nos executar várias ações em diferentes Threads. Várias classes da
framework .NET suportam este padrão através do fornecimento de métodos que
seguem a cnvenção BeginXXX e EndXXX. Para demonstrar este mesmo padrão, iremos
utilizada o método Read da classe Stream.
Primeiro, vejamos a versão sincrona:
public int Read (byte[] buffer, int offset, int size);
De seguida, a versão que suporta APM:
public IAsyncResult BeginRead (byte[] buffer, int offset, int size, AsyncCallback callback, object state);
public int EndRead (IAsyncResult asyncResult);
Outra particularidade é o tipo de retorno que está envolvido nestes métodos da versão
APM. O método que inicia a operação (Begin) devolve um objecto do tipo IAsyncResult
que, basicamente, é um token que representa a operação.
Existe também um callback, que é basicamente uma função que será executada
mediante certas condições. Neste caso concreto, este callback só é executado quando a
operação assíncrona termina ou quando ocorre um erro na sua realização.
A definição do callback é dada pelo seguinte delegate:
public delegate void AsyncCallback (IAsyncResult ar);
Quem tratar deste callback/delegate invoca o método que devolve o resultado final da
operação assíncrona (End). É também responsável por re-lançar um erro caso este
ocorra.
4
5. Modelo APM em .NET
por
Pedro Gabriel
Vejamos então código-fonte que demonstra este padrão:
É de notar então, que na construcção do objecto do tipo FileStream é necessária a
indicação da intenção futura de realizar uma leitura assíncrona. De modo a realizar a
leitura deste mesmo modo, são invocados os métodos que suportam a versão APM,
BeginRead e EndRead. O primeiro recebe todos os argumentos que o método Read
recebe, e mais dois que efectuam o suporte ao modelo APM - Callback e Object-State.
Note-se ainda o retorno de uma objecto IAsyncResult que é posteriormente passado ao
método End para obter o resultado final.
5
6. Modelo APM em .NET
por
Pedro Gabriel
Rendezvous 1 - Wait-Until Done:
Este tipo de rendezvous permite iniciar uma acção assíncrona, realizar outro trabalho, e
posteriormente voltar para verificar se a acção foi completada entretanto. A verificação
irá bloquear até que a acção seja completada.
Percebemos então que, qualquer código que seja colocado entre as chamas dos
métodos APM será executado enquanto o mesmo pedaço de código lê o ficheiro de
texto. É uma abordagem possivel para aplicações que pretendam ter um grau de
resposta alto perante um elevado número de acções a realizar.
6
7. Modelo APM em .NET
por
Pedro Gabriel
Rendezvous 2 - Polling :
Este tipo de rendezvous envolve a Thread que pretende ser notificada directamente, ou
seja, é esta que tem de verificar, ao longo de um periodo, a realização da acção
assíncrona que iniciou. Tem a vantagem de não bloquear enquanto realiza as
verificações. A verificação é feita através da chamada da propriedade de IsComplete do
resultado devolvido pelo método BeginXXX.
Código acima demonstra que, é possivel realizar outro trabalho, à medida que se
verifica a realização da acção inicial, sem que esta bloqueie a Thread envolvida.
7
8. Modelo APM em .NET
por
Pedro Gabriel
Rendezvous 3 - Callback :
Este último rendezvous obriga à passagem de um método callback que será executado
quando a acção assíncrona terminar ou se gerar erro. É desta forma que ficamos a saber
que a acção terminou. Por esta lógica, é dentro do callback que iremos obter o resultado
final da nossa acçao assíncrona, através do método EndXX.
Na prática, o que o método BeginXX está a fazer é colocar a acção assíncrona numa fila
de acções (queue), que através de Threads mantidas pela ThreadPool internal do .NET,
será realizada mais tarde. A forma que a framework tem de avisar a Thread que iniciou a
acção é invocar o callback fornecido pela Thread inicial.
Se o callback for:
Então a chamada será feita da seguinte forma:
fs.BeginRead(s_data, 0, s_data.Length, ReadIsDone, fs);
Como podemos ver, a obtenção do resultado é feita dentro do callback. O mesmo
resultado é tratado lá dentro, uma vez que não é permitido qualquer retorno. Relembro
que a assinatura do método tem que satisfazer o delegate demonstrado anteriormente.
8