2010-08-09 20 views
16

Ho appena scoperto il MailboxProcessor in F # e il suo utilizzo come "macchina di stato" ... ma non riesco a trovare molto sull'uso raccomandato di essi.Linee guida per l'utilizzo di MailboxProcessor?

Ad esempio ... dire che sto realizzando un gioco semplice con 100 nemici sullo schermo se dovessi usare un MailboxProcessor per cambiare posizione e salute del nemico; dandomi 200 MailboxProcessor attivo?

C'è qualche gestione intelligente del thread in corso sotto il cofano? dovrei provare a limitare la quantità di MailboxProcessor attivo che ho o posso continuare a batterli volenti o nolenti?

Grazie in anticipo,

JD.

risposta

6

Come per

http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx

si può battere li fuori, volenti o nolenti. Provalo! Usano il ThreadPool. Non l'ho provato per un'applicazione di GUI in tempo reale, ma non sarei sorpreso se fosse abbastanza "buono".

+0

Come ho sottolineato nella mia risposta di seguito, in caso di molti molti nemici sullo schermo, se si fa un agente per enimy, una volta ricevuto un messaggio, probabilmente farà una quantità di lavoro non banale, quindi proverai eseguire una quantità enorme di lavoro che tenta di essere parallelo. Non c'è alcun motivo per farlo: ci sono solo così tanti thread che il tuo processore può davvero funzionare in parallelo. Così hai tanti processori quanti ne hai e dividi i nemici tra loro. –

+0

Il ThreadPool lo farà per lo più, sì? Crea il lavoro più "parallelo" che desideri e lascia che il ThreadPool faccia il suo lavoro per pianificare il lavoro in modo significativo. – Brian

+0

Si ottiene un sovraccarico del pool di thread per messaggio che non è del tutto eccezionale. Ho ampliato la mia risposta qui sotto per spiegare i trade-off. –

12

Un MailboxProcessor per nemico simulazione potrebbe essere simile a questo:

MailboxProcessor.Start(fun inbox -> 
async { 
    while true do 
    let! message = inbox.Receive() 
    processMessage(message) 
}) 

non consuma un filo mentre si attende un messaggio per arrivare (let! message = line). Tuttavia, una volta arrivato il messaggio, verrà utilizzato un thread (in un pool di thread). Se disponi di 100 processori di caselle postali che ricevono tutti un messaggio simultaneamente, tenteranno tutti di svegliarsi e consumare un thread. Poiché qui l'elaborazione dei messaggi è vincolata dalla CPU, 100s dei processori della casella di posta si sveglieranno e avvieranno i thread di spawning (pool di thread). Questa non è una grande prestazione.

Una situazione in cui i processori delle cassette postali eccellono è la situazione in cui sono presenti numerosi client concorrenti che inviano tutti messaggi a un processore (immaginate diversi web crawler paralleli che scaricano tutte le pagine e affondano i risultati in una coda). Il caso dei nemici sullo schermo appare diverso: sono molte le entità che rispondono a una singola fonte di messaggi (movimento del giocatore/battiti del tempo).

Un altro esempio in cui migliaia di MailboxProcessors è una grande soluzione è di I/O MailboxProcessor bound:

MailboxProcessor.Start(fun inbox -> 
async { 
    while true do 
    let! message = inbox.Receive() 
    match message with 
    | -> 
     do! AsyncWrite("something") 
     let! response = AsyncResponse() 
     ... 
}) 

Qui dopo aver ricevuto un messaggio l'agente produce molto rapidamente un filo, ma ancora ha bisogno di mantenere lo stato tra le operazioni asincrone. Questo si ridurrà molto bene nella pratica - è possibile eseguire migliaia e migliaia di tali agenti: questo è un ottimo modo per scrivere un server web.

+0

"Se si dispone di 100 processori di cassette postali che ricevono tutti un messaggio contemporaneamente, si sveglieranno tutti e tenteranno di consumare un thread." - Non mi sembra giusto. Ho scritto alcune applicazioni che fanno uso non banale di MailboxProcessors e il numero di thread attivi in ​​un dato momento è determinato dal pool di thread, che a sua volta è determinato (credo) dal numero di processori sulla tua macchina . Anche toccando 100 caselle di posta contemporaneamente, non ho mai visto più di pochi thread attivi in ​​un dato momento. – Juliet

+1

Giulietta, giusto, avrei dovuto dire "tentativo di svegliarsi". Fare la fila per l'esecuzione del pool di thread non è economico. –

4

dire che sto facendo un semplice gioco con 100 nemici sullo schermo dovrei usare un MailboxProcessor per cambiare posizione e salute del nemico; dandomi 200 MailboxProcessor attivo?

Non vedo alcun motivo per provare a utilizzare MailboxProcessor per quello. È probabile che un ciclo seriale sia molto più semplice e veloce.

C'è qualche gestione intelligente del thread in corso sotto il cofano?

Sì, molto. Ma è progettato per la programmazione simultanea asincrona (in particolare IO scalabile) e il tuo programma in realtà non lo fa.

devo provare e limitare la quantità di MailboxProcessor attivo che ho o posso continuare a batterli fuori volenti o nolenti?

È possibile batterli volenti o nolenti, ma sono ben lontani dall'ottimizzazione e le prestazioni sono molto peggiori rispetto al codice seriale.

Problemi correlati