Programação Paralela em Arquiteturas Multi-Core/Aplicações Internet: diferenças entre revisões

[edição não verificada][edição não verificada]
Conteúdo apagado Conteúdo adicionado
Linha 205:
*Ambientes de programação
*Bibliotecas de programação
*=== Linguagens de programação ===
 
**PHP
O aumento da velocidade da conexão à internet pela maioria dos usuários permitiu que as páginas na web se tornassem verdadeiras aplicações, podendo até mesmo susbstituir algumas (como um editor de texto ou uma planilha eletrônica) que à pouco tempo atrás pensou-se ser inviável.
**Java
 
*Tecnologias
Essa sessão apresentará algumas linguagens voltadas para web e como tratar questões de paralelização e concorrência em cada uma delas.
**AJAX
 
**CGI
==== Java Script ====
 
Essa sessão terá como foco como carregar componenetes em paralelo em um site em HTML. Esses componenets podem ser arquivos em javascript, podendo ser extendidos a arquivos css, ou imagens. Ápos isso será abordado a questão do AJAX principalmente usando o objeto XmlHttpResquest.
 
===== Carregando componentes em paralelo =====
 
O número de conexões HTTP que o cliente abre com o servidor é definida pelo navegador. Navegadores atuais geralmente abrem muitas conexões com o mesmo site quando se requisita uma página (esse número de conexões depende do navegador em questão[http://www.mozilla.org/quality/networking/docs/netprefs.html], mas navegadores antigos abrem no máximo duas conexões com o servidor [http://support.microsoft.com/kb/183110]. Isso permite que o navegador faça download dos componentes paralelamente, baixando o site mais rápido. Figuras são um bom exemplo de componentes que são baixados paralelas, automaticamente, pelo navegador. Mas arquivos javascript não são.
 
Quando você carrega arquivos em javascript na sua página, na forma usual, eles são carregados em sequência:
 
<pre>
<script src="Arquivo1.js" type="text/javascript"></script>
<script src="Arquivo2.js" type="text/javascript"></script>
</pre>
 
fig1
 
O tamanho dos arquivo em javascript tem crescido muito, e está se tornando comum páginas com chamadas à muitos arquivos grandes. Isso pode deixar a página lenta e bem de desagrádavel para o usuário. A saída é carregar esses arquivos em paralelo:
 
fig2
 
é claro que se a conexão do usuário é ruim carregar os scripts em paralelo não resolve muita coisa.
 
Uma das maneiras de se fazer isso é usar um document.write:
 
 
<pre>
<script type="text/javascript">
 
document.writeln("<script src='Arquivo1.js' type='text/javascript'><" + "/script>");
 
document.writeln("<script src='Arquivo2.js' type='text/javascript'><" + "/script>");
 
</script>
</pre>
 
O navegardor abrirá duas conexões com o host e fazendo os downlaods dos arquivo em paralelo. Entretanto a execução dos mesmo é sequencial. Mas se Arquivo2.js for carregado e o usuário pára o carregamento da página enquando o Arquivo1 ainda é baixado o Arquivo2.js será executado (isso pode não ser válido para o internet explorer).
O número de arquivos, ou qualquer outro componente que é baixado separadamente como imagens, que podem ser baixados em paralelo, usando esse esquema, é limitado pelo número de conexões que navegador pode fazer com o host. Para se estender o número de conexões paralelas é necessário mudar o nome do host, criando alias para o nome do host, por exemplo imagens1.exemplo.com e imagens2.exemplo.com.
<pre>
<img src="imagem1.png" />
 
<img src="imagem2.png" />
 
<img src="http://imagens1.examplo.com/imagem3.png" />
 
<img src="http://imagens1.example.com/image4.png" />
 
<img src="http://imagens2.example.com/image5.png" />
 
<img src="http://imagens2.example.com/image6.png" />
</pre>
 
Atualmente os navegadores abrem muitas conexões em paralelo, e ainda é póssivel aumentar esse número. Esse último esquema é mais útil para navegadores limitados a somente duas conexões.
 
 
===== AJAX - Requisições Concorrentes =====
 
A algum tempo atrás o modelo clássico das aplicações na web era puramente sequêncial. Você tinha uma seqüência de chamadas de funções e elas sempre eram executadas em uma certa ordem. Mas a forma de programar para web mudou. As aplicações aumentaram de porte. Muito disso deve-se ao conjunto de tecnologias AJAX.
 
A razão pela qual o AJAX se tornou tão popular deve-se a sua capacidade de realizar ações concomitantes ou por "traz dos panos" para o usuário. Entretanto não existe uma real concorrência em javascript, muito menos processamento paralelo. Mas é póssivel criar uma ilusão de certo grau de concorrência.
 
Um dos modos de se trabalhar com AJAX é recuperando os dados de forma assíncrona usando o objeto XMLHttpRequest. Há duas maneiras de se fazer uma requisição com um objeto XMLHttpRequest, uma é síncrona, outra assíncrona. No modo síncrono, quando você manda o objeto fazer uma requisição, o seu script é interrompido esperando pelo retorno. Quando a chamada é assíncrona, logo que a chamada é feita o fluxo de execução volta para o script, permitindo que ele execute outras funções ou ainda outras chamadas ao objeto. Como a essa chamadas não são realmente concorrentes a ordem que elas são feitas é um fator importante. O que define uma chamada como síncrona ou assíncrona é o terceiro parâmetro do método open do objeto. Um modelo clássico de fazer chamadas ao XMLHttpRequest é esse:
 
<pre>
var req;
function loadXMLDoc(url)
{
req = null;
// Procura por um objeto nativo (Mozilla/Safari)
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send(null);
// Procura por uma versão ActiveX (IE)
}
else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req) {
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send();
}
}
}
 
function processReqChange()
{
if (req.readyState == 4) {
if (req.status == 200) {
document.getElementById('teste').innerHTML += '<br><br> Nova Requisição'+req.responseText;
} else {
alert("Houve um problema ao obter os dados:\n" + req.statusText);
}
}
}
</pre>
 
Fazer chamadas ao ao método open em sequência, sem que a primeira chamada tenha sido concluída costuma não funcionar e os resultados são inesperados. O que gerealmente é feito é criar uma fila de chamadas e executa-las sequencialmente:
 
<pre>
function insereFila(id,url){
//insere na fila
fila[fila.length]=[id,url];
//Se não há conexões pendentes, executa
if((ifila+1)==fila.length)executa();
}
 
//Executa a próxima conexão da fila
function executa(){
req.open("GET",fila[ifila][1],true);
req.onreadystatechange=function() {
if (xmlhttp.readyState==4){
document.getElementById(fila[ifila][0]).innerHTML=req.responseText;
//Roda o próximo
ifila++;
if(ifila<fila.length)setTimeout("executa()",20);
}
}
req.send(null);
}
</pre>
 
Ou ainda é póssivel criar outros objetos XMLHttpRequest.
 
 
 
==== PHP ====
 
PHP não é uma linguagem multithread, mas é póssivel simular paralelismo utilizando multiprocesso. Quando um processo pai cria um processo filho ambos os processos são executados concorrentemente. Isso é póssivel em PHP através do PHP Process Control Functions (PNCTL). Para isso o pacote PHP deve ser compilado com a opção --enable-pcntl, disponível somente em sistemas linux.
 
Essas função não deveriam ser usadas dentro de um servidor web e resultados inesperados podem ser obtidos quando isso é feito [http://www.php.net/manual/en/ref.pcntl.php].
 
Esse é um exemplo simples de criação de um processo em PHP:
 
<pre>
$pid = pcntl_fork();
 
if($pid) {
//o que deve ser rodado no processo pai
echo "pai";
}
else {
// o que deve ser rodado no processo filho
echo "filho";
}
</pre>
 
===== Principais funções =====
 
Essas são as principais funções para criação e manipulação de processos:
 
* Int pcntl_alarm (interno $ segundos)
 
Cria um temporizador que envia um sinal SIGALRM para um processo. Qualquer nova chamada a pcntl_alarm cancela a anterior.
 
* void pcntl_exec ( string $path [, array $args [, array $envs ]] )
 
Executa um programa no espaço de mémoria do processo conrrente. O primeiro argumento é o caminho para o programa. O segundo é um vetor de argumentos passados ao programa.
 
* int pcntl_fork ( void )
 
Essa função cria um processo filho que difere do precesso pai pelo PID ou PPID. Equivale à uma chamada ao fork() do sistema.
 
* bool pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls ] )
 
envia um sinal definido por signo.
 
* int pcntl_wait ( int &$status [, int $options ] )
 
O processo atual suspende sua execução e aguarda até que determinado sinal seja emitido.
 
 
==== JAVA ====
 
Nessa seção estaremos vendo detalhes da implementação de aplicações multitarefa usando a linguagem Java.
 
A linguagem Java fornece uma classe chamada Thread a partir da qual o programador pode criar suas próprias threads. Para isso, é preciso que o programador estenda essa classe e implemente as devidas customizações, reescrevendo o método run().
 
<pre>
public class ThreadSimples extends Thread {
public ThreadSimples(String str) {
super(str);
}
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i + " " + getName());
try {
sleep((long)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("Pronto! " + getName());
}
}
</pre>
 
O método run() é onde colocamos toda a lógica de execução da thread. O método run() da classe ThreadSimples contém um loop que é executado 100 vezes. Em cada iteração, o método exibe na saída-padrão do sistema o número correspondente àquela iteração e o nome que foi associado à thread. Então, a thread entra em modo de espera de acordo com o retorno da chamada Math.random(). Quando o loop termina, o método run imprime Pronto! seguido do nome da thread.
 
No exemplo a seguir é usado duas threads da classe acima:
 
<pre>
public class exemplo {
public static void main (String[] args) {
new ThreadSimples("Jamaica").start();
new ThreadSimples("Fiji").start();
}
}
</pre>
 
Uma outra técnica que pode ser utilizada para implementação de threads na linguagem Java é o uso da interface Runnable:
 
<pre>
import java.awt.Graphics;
import java.util.*;
import java.text.DateFormat;
import java.applet.Applet;
 
public class Relogio extends Applet implements Runnable {
 
private Thread clockThread = null;
 
public void start() {
if (clockThread == null) {
clockThread = new Thread(this, "Clock");
clockThread.start();
}
}
 
public void run() {
Thread myThread = Thread.currentThread();
while (clockThread == myThread) {
repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e){
...
}
}
}
 
public void paint(Graphics g) {
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
DateFormat dateFormatter = DateFormat.getTimeInstance();
g.drawString(dateFormatter.format(date), 5, 10);
}
 
public void stop() {
clockThread = null;
}
}
</pre>
 
== Conclusão ==