Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In esercitazione II abbiamo illustrato come gestire un servizio dispendioso in termini di tempo usando una sessione durevole. Tuttavia, la modalità batch non è l'unica modalità di calcolo nel mondo HPC. Alcuni calcoli possono essere completati entro pochi secondi. L'utente finale potrebbe aspettarsi una risposta quasi in tempo reale.
Questa modalità comporta diverse sfide rispetto alla modalità batch. Il tempo di risposta è più critico. Non è pertanto possibile ignorare il sovraccarico di avvio della sessione. In un tipico cluster HPC, l'avvio di una nuova sessione richiede alcuni secondi. Se nel cluster sono in esecuzione altri processi, la sessione appena creata deve attendere fino a quando le risorse non sono disponibili, il che rende il tempo di avvio molto più lungo. Fortunatamente, HPC Pack offre un modo per gestire questa situazione e ridurre il costo non necessario.
Per seguire la procedura descritta in questo articolo, vedere l'di esempio di codice a cui è associata.
Implementare il servizio
Viene usato lo stesso servizio di esercitazione II, ovvero il servizio di fattorizzazione prime. Per soddisfare i requisiti in tempo reale, si passeranno solo piccoli numeri al servizio.
Ecco il contratto di servizio:
[ServiceContract]
public interface IPrimeFactorization
{
[OperationContract]
List<int> Factorize(int n);
}
Ed ecco l'implementazione del servizio:
public List<int> Factorize(int n)
{
List<int> factors = new List<int>();
for (int i = 2; n > 1;)
{
if (n % i == 0)
{
factors.Add(i);
n /= i;
}
else
{
i++;
}
}
return factors;
}
Implementare il client
Per risparmiare tempo di avvio del nuovo processo, il client deve riutilizzare la sessione esistente anziché crearne una nuova, perché la creazione di una nuova sessione significa avviare un nuovo processo. Per riutilizzare la sessione esistente, è necessario creare la sessione come indicato di seguito:
const string headnode = "head.contoso.com";
const string serviceName = "PrimeFactorizationService";
SessionStartInfo info = new SessionStartInfo(headnode, serviceName);
//Enable session pool
info.ShareSession = true;
info.UseSessionPool = true;
È possibile notare che sono disponibili due nuove proprietà di SessionStartInfo assegnate qui.
L'impostazione di ShareSession su true significa che qualsiasi utente può inviare richieste al broker, non solo a quello che crea la sessione.
L'impostazione di UseSessionPool su true garantisce che ogni nuovo client usi la sessione esistente anziché crearne un'altra. Il pool di sessioni viene mantenuto sul lato server. Garantisce che quando un client si connette allo stesso servizio con il flag impostato su true, restituisce sempre la stessa sessione purché sia ancora attiva.
È ora possibile creare la sessione. Non si vuole usare una sessione durevole perché può influire sulle prestazioni.
//create an interactive session
using (Session session = Session.CreateSession(info))
{
Console.WriteLine("Session {0} has been created", session.Id);
…
}
Creare un client broker per inviare richieste e ottenere risposte.
Nel caso del codice precedente, è ora presente una situazione in cui possono essere presenti molti client broker in una singola sessione. In questo caso, è necessario assegnare un ID univoco al client.
//in one session, each broker client should have a unique id
string ClientId = Guid.NewGuid().ToString();
using (BrokerClient<IPrimeFactorization> client = new BrokerClient<IPrimeFactorization>(ClientId, session))
{
Console.WriteLine("BrokerClient {0} has been created", ClientId);
Random random = new Random();
int num = random.Next(1, Int32.MaxValue);
//Send request
FactorizeRequest request = new FactorizeRequest(num);
client.SendRequest<FactorizeRequest>(request, num);
client.EndRequests();
//Get response
foreach (BrokerResponse<FactorizeResponse> response in client.GetResponses<FactorizeResponse>())
{
int number = response.GetUserData<int>();
int[] factors = response.Result.FactorizeResult;
Console.WriteLine("{0} = {1}", number, string.Join<int>(" * ", factors));
}
}
Eseguire ora il client due volte. Si noterà che i client condividono lo stesso ID sessione, come risultato del pool di sessioni abilitato. Inoltre, il primo client viene eseguito molto più a lungo del secondo, che indica che il nuovo client riutilizza la sessione creata.
Poiché GetResponses è una funzione sincrona, il client verrà bloccato e mantenuto in attesa dei risultati. Questa non è una situazione di benvenuto in un sistema in tempo reale, quindi cerchiamo un altro modo per ottenere risposte.
È possibile impostare un callback asincrono per il client usando SetResponseHandler come indicato di seguito:
//use this event sync main thread and callback
AutoResetEvent done = newAutoResetEvent(false);
//set callback function. this handler will be invoke before service replies.
client.SetResponseHandler<FactorizeResponse>((response) =>
{
int number = response.GetUserData<int>();
int[] factors = response.Result.FactorizeResult;
Console.WriteLine("{0} = {1}", number, string.Join<int>(" * ", factors));
//release the lock
done.Set();
});
Di conseguenza, dopo l'invio delle richieste, il client può continuare con altre operazioni. Quando le risposte sono pronte, il gestore della risposta verrà chiamato per visualizzare i risultati.
Distribuire e testare il servizio
È possibile seguire questa esercitazione per distribuire e testare il caso in modo dettagliato.
È possibile eseguire più client. L'output sarà simile al seguente:
Si noti che tutti i client condividono lo stesso ID sessione.
Aumento automatico e riduzione automatica del cluster
Una situazione comune della modalità interattiva consiste nell'eseguire un servizio a esecuzione prolungata che gestisce più client. Per rispondere a ogni richiesta il più rapidamente possibile, è necessario mantenere attiva la sessione. Ma, d'altra parte, avere un lavoro SOA occupa un gran numero di risorse durante i periodi di minore attività è sprecato.
HPC Pack offre una funzionalità per aumentare e ridurre le risorse in base al numero di richieste. Se non sono presenti richieste, il numero di risorse verrà ridotto al numero minimo specificato dal processo. Quando si ricevono richieste, aumenta automaticamente le risorse per gestirle.
Nota: si verifica un timeout di una sessione se non è presente alcun client che vi si connette per un periodo di tempo. Per rendere una sessione un servizio a esecuzione prolungata, è possibile modificare il sessionIdleTimeout