Windows Phone 7, a nova plataforma móvel de Microsoft

Um dos lançamentos com mais novidade ultimamente foi o sistema operativo Windows Phone 7.

Por José Ángel Fernández-Tradução CRV


Publicado em: 27/8/12
Valorize este artigo:
A programação assíncrona se converteu em uma necessidade para evitar o bloqueio da interface de usuário quando executamos tarefas mais longas de uns poucos milissegundos: acesso a recursos remotos, leitura de arquivos em disco, cálculos muito longos, etc. Qualquer bloqueio do UI, embora seja de meio segundo, dará a sensação de uma baixa qualidade da aplicação. Por este motivo foram sendo desenvolvidos mecanismos que nos facilitem a tarefa de manejar diferentes fios de execução.

Neste artigo vocês vão encontrar uma breve introdução aos diferentes modelos de execução assíncrona que temos em .Net e como podemos utilizar alguns dos novos que não vêm de serie em Windows Phone 7, como acontece com TPL.

Um pouco de historia (subjetiva)

Antes de existir a programação multifios e muito antes dos processadores multinúcleo, os usuários de quase qualquer aplicação tínhamos que esperar uma eternidade para que se realizassem certas operações. Alguns aproveitavam para fazer outras coisas como tomar um café, ir ao banheiro, dar um passeio pelo bosque, outros nos entretínhamos com o barulhinho que fazia a fita do Spectrum enquanto carregava um programa jogo. Eram outros tempos e os poucos usuários que éramos levávamos a vida com filosofia e muitos cafés.

Pouco a pouco os usuários se tornaram cada vez mais impacientes exigentes e deixaram de admitir aquelas agradáveis pausas que lhes oferecíamos os programadores para que pudessem relaxar e relacionar-se com seus companheiros. Os fabricantes de sistemas operativos criaram a multitarefa: podíamos utilizar varias aplicações simultaneamente, assim que os usuários viram a luz e se tornaram muito pesados com o resto dos desenvolvedores, os pobres mortais que escreviam aplicações de gerenciamento, exigindo que as aplicações não ficassem paradas enquanto realizavam alguma complicada operação que lhes parecia demorar demasiado.

Por muito que otimizemos, existem milhares de esperas que não dependem de nós. Alguns tiveram a ideia de que valia mais parecer rápido que sê-lo e viram que a solução era utilizar o tempo em que o processador estava ocioso para realizar as tarefas longas, procurando não influir demasiado sobre o rendimento do interface de usuário.

Padrões multifio

Tudo isto nos levou até nosso velho companheiro o subprocesso (ou fio), que permitia fazer tudo isto e muito mais, utilizando técnicas muito complexas como os bloqueios, semáforos e mensagens para poder sincronizar os diferentes fios.

A programação com milhares de fios pode chegar a ser muito complicada e difícil de entender, pois ao estarmos acostumados a uma linguagem imperativa para programar (como no nosso caso C#) tendemos a pensar na execução de maneira sequencial. Quando utilizamos múltiplos fios rompemos essa sequencia em tarefas que podem ser executadas em paralelo.

Em .Net podemos fazer uso da classe Thread que encapsula a funcionalidade dos fios do sistema operativo, mas para nos facilitar as tarefas mais comuns surgiram outros dois padrões de desenvolvimento de métodos assíncronos. Estes dois padrões nos facilitaram muito a tediosa tarefa de ir criando, mantendo e sincronizando diferentes fios de execução:

  • APM ou Asynchronous Programming Model: graças ao modelo de programação assíncrona pudemos poupar escrever o mesmo código uma ou outra vez para criar um fio em segundo plano que realizará essas tarefas. O modelo consiste em uma dupla de métodos Begin e End: em Begin passaremos um método "callback" que será chamado ao acabar a execução e utilizaremos End para recuperar a informação que processou o método assíncrono.
  • EAP ou Event-based Asynchronous Pattern: aqui temos um método OperationAsync para lançar a execução assíncrona e um evento OperationCompleted onde receberemos os dados. Em Silverlight o conhecemos bem porque o utilizamos em milhares de classes, como por exemplo WebClient.DownloadStringAsync e WebClient.DownloadStringCompleted
As classes que implementam EAP podem ser usadas criando manipuladores de eventos explícitos, tal como usamos os eventos de pressão de um botão. Também podemos utilizar métodos anônimos para facilitar um pouco sua leitura.

Utilizando um manipulador de evento explícito podemos tratar o resultado do método assíncrono quando este acaba sua execução da seguinte maneira:

public void BaixarDados()
{
var webClient = new WebClient();
webClient.DownloadStringCompleted += webClientDownloadStringCompleted;
webClient.DownloadStringAsync(new Uri("http://jmservera.wordpress.com/feed/"));
this.contenedor.Text="DownloadComeçado";
}

private void webClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
this.contenedor.Text=e.Result;
}

Quando usamos este método em Silverlight o sistema voltará a sincronizar o fio de UI no evento Completed para que não tenhamos que utilizar explicitamente o Dispatcher. Pode ser que alguma implementação de chamada assíncrona EAP não tenha em conta esta característica da programação no UI.

Com este modelo temos o manipulador do resultado algo longe da chamada e em códigos muito longos podemos perder um pouco a perspectiva do que estamos fazendo.

Graças aos métodos anônimos podemos escrever diretamente dentro do mesmo método, o que nos facilitará um pouco a legibilidade de nosso código:

public void BaixarDados()
{
var webClient = new WebClient();
webClient.DownloadStringCompleted += (o,e) =>
{
this.container.Text=e.Result;
};
webClient.DownloadStringAsync(new Uri("http://jmservera.wordpress.com/feed/"));
this.contenedor.Text="DownloadComeçado";
}

Ainda assim a sequência natural não se vê refletida no código, pois a ação que pretendemos realizar depois do download deve ser indicada antes de chamar a sua execução. Nos falta o código desordenado.

Task Parallel Library

TPL é uma biblioteca pensada para paralelizar tarefas de maneira simples e assim melhorar o rendimento de nossa aplicação. Embora seu foco seja outro, também nos ajuda a criar tarefas assíncronas e encadeá-las na ordem em que vão ser executadas.

public void BaixarDadosTPL()
{
var syncContext= TaskScheduler.FromCurrentSynchronizationContext();
var webClient = new WebClient();
//executamos a tarefa assincrona
webClient.DownloadStringTaskAsync(new Uri("http://jmservera.wordpress.com/feed/"))
.ContinueWith((s) =>
{
//e continuamos depois de finalizar o download
conteudo.Text = s.Result;
}, syncContext);

// aqui continuamos no fio principal enquanto se executa a tarefa
// de download
conteudo.Text = "Baixando...";
}

Como podemos ver no código, as chamadas se encadeiam em tarefas na sequencia natural, primeiro baixamos e depois utilizamos o resultado.

Para poder atribuir o texto ao container utilizamos um TaskScheduler que sincronizará automaticamente o fio de execução com o contexto que nós indiquemos, não temos que nos preocupar com chamar o Dispatcher, se precisar o TaskScheduler se encarregará disso por nós.

TPL para Windows Phone 7

Para poder usar TPL em WP7 necessitaremos recorrer à versão que há disponível para download a través de NuGet. Dado que não é a versão oficial, não teremos o método DownloadStringTaskAsync en el WebClient. TPL tem um wrapper para poder converter métodos APM em TPL. Para os EAP não existe um, mas podemos criá-lo utilizando a classe TaskCompletionSource. Para nosso exemplo criaremos um método de extensão e assim se parecerá mais aos novos métodos que estão por vir; haverá que ir com cuidado ao liberar os manipuladores de evento:

public static class WebClientExtension
{
public static Task<string> DownloadStringTaskAsync(this WebClient webClient, Uri uri)
{
TaskCompletionSource<string> tcs =
new TaskCompletionSource<string>();

DownloadStringCompletedEventHandler completedHandler = null;
completedHandler=(o, e) =>
{
if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else
{
tcs.TrySetResult(e.Result);
}
//ha que limpar referencias para
//evitar problemas de memoria
webClient.DownloadStringCompleted -= completedHandler;
};

webClient.DownloadStringCompleted += completedHandler;
try
{
webClient.DownloadStringAsync(uri);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
webClient.DownloadStringCompleted -= completedHandler;
}
return tcs.Task;
}
}

Uma vez criada a tarefa desta maneira poderemos chamar o método DownloadStringTaskAsync como fizemos no exemplo anterior.

Lança e Espera com Async e Await

Como vimos, pouco a pouco vamos melhorando a legibilidade do código, de maneira que nosso código se pareça cada vez mais ao código que escreveríamos se realizássemos a operação de maneira síncrona. A última melhoria foi a criação das novas construções da linguagem async e await.

Durante o Mix 2011 foi anunciada a Community Technology Preview de Async, uma nova característica da linguagem C# para a criação de funções assíncronas, que está madurando e, como se viu no Build Windows, já faz parte do framework 4.5. A nova maneira de escrever nosso código será esta:

async void BaixarDadosAsync()
{
var webClient = new WebClient();
var data = await webClient.DownloadStringTaskAsync(
new Uri("http://jmservera.wordpress.com/feed/"));
this.container.Text = data;
}

O truque está na palavra reservada await que indica ao compilador que chamamos um método assíncrono e que deve continuar a execução até que encontre código que solicita os dados esperados do método assíncrono. Para isso o compilador criará uma máquina de estados que gerará os métodos necessários para manejar os callbacks que sejam necessários.

Para Windows Phone 7.1 a última versão da Async CTP não funciona, assim que para testá-la vocês vão precisar do Visual Studio 11 Developer Preview.

Quando chamemos o método BaixarDadosAsync nosso código não parará aí, continuará a execução e quem se encarrega de tudo isto é o próprio compilador de C#.

Você sabe qual foi o primeiro sistema operativo doméstico com multitarefa preemtiva? Descubra-o nos links deste artigo.

De que necessito?






Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor

Home | Sobre nós | Copyright | Anuncie | Entrar em contato