Devo riutilizzare un predicato per più controlli IEnumerable

0

In un servizio Windows di lunga esecuzione ho un gestore di pool di thread personalizzato che ha un ciclo che controlla continuamente un paio di elenchi per i thread inattivi.

Dati molteplici usi dello stesso predicato, c'è qualche vantaggio nel salvare il lambda come Func?
In che modo la raccomandazione potrebbe cambiare in base al numero di thread con cui sta interagendo questo codice o quando è possibile che Func possa essere passato ad altri metodi per facilitare il lavoro?

while (_isRunning )
{
  ...sleep a bit to prevent thrashing
  while ( _threads.Any(t => t.IsIdle) || _autreThreads.Any(t => t.IsIdle)
  {
    var assignee = _threads.FirstOrDefault(t => t.IsIdle) ?? _autreThreads.FirstOrDefault(t => t.IsIdle);
    ...give 'em something to do 
  }
}

Al posto di ciascuno dei lambda potrei usare quanto segue, definito una volta all'esterno per il ciclo, per il riutilizzo.

Func<WorkerThread, bool> isIdleCondition = t => t.IsIdle;
    
posta rediVider 29.11.2018 - 02:11
fonte

3 risposte

2

Tieni presente che t => t.IsIdle è tanto una costante letterale quanto 5 o "Hello world" . Non cambia mai, il compilatore lo vede, e quindi sa che la funzione è una costante che non ha bisogno di essere riattivata ogni volta che il metodo viene eseguito.

How might the recommendation change based on the count of threads this code is interacting with, or when the Func might need to be passed to other methods to help with the work?

Non è così. Anche se messo in una proprietà separata, hai sempre intenzione di ottenere questa proprietà, non impostarla mai, quindi non ci sarà alcun problema in quanto la funzione sarà sempre disponibile e le condizioni di gara non sono -existant.

In place of each of the lambdas I could use the following, defined once outside for the loop, for reuse.

L'unica ragione per inserirla in una proprietà se per motivi di leggibilità e riusabilità . Non c'è alcuna differenza significativa per le prestazioni di runtime.

Quindi vorrei ancora difenderlo mettendolo in una proprietà a sé stante, ma non per i motivi che stai chiedendo nella tua domanda.

    
risposta data 29.11.2018 - 09:31
fonte
3

Penso che tu stia focalizzando la tua attenzione nel posto sbagliato per iniziare.

while ( _threads.Any(t => t.IsIdle) || _autreThreads.Any(t => t.IsIdle) )
{
    var assignee = _threads.FirstOrDefault(t => t.IsIdle) ?? _autreThreads.FirstOrDefault(t => t.IsIdle);
    ...give 'em something to do 
}

Essenzialmente sta facendo il doppio lavoro, prima di tutto per verificare l'esistenza di un thread inattivo. _threads.Any(t => t.IsIdle) || _autreThreads.Any(t => t.IsIdle) quindi per ottenere quel thread _threads.FirstOrDefault(t => t.IsIdle) ?? _autreThreads.FirstOrDefault(t => t.IsIdle);

Puoi tagliare a metà il lavoro in questo modo:

ThreadType assignee = null
while (null != (assignee = _threads.FirstOrDefault(t => t.IsIdle) ?? _autreThreads.FirstOrDefault(t => t.IsIdle)))
{
    ...give 'em something to do 
}

Ora troviamo e prendiamo il thread inattivo in un solo passaggio.

Ancora ci sono altri problemi qui, quindi evita di attaccare il lambda, e invece chiedi perché devi iterare questi due elenchi in modo indipendente?

ThreadType assignee = null
while (null != (assignee = _threads.Union(_autreThreads).FirstOrDefault(t => t.IsIdle)))
{
    ...give 'em something to do 
}

Ora valutiamo pigro entrambi gli elenchi, trovando il primo thread inattivo.

Potresti spingere il lambda in una funzione ora, ma perché il lavoro del compilatore?

    
risposta data 29.11.2018 - 07:53
fonte
0

Può essere di aiuto in alcuni casi con la leggibilità e può essere utile occasionalmente in caso di modifiche, quindi non è necessario correggere due posizioni.

Tuttavia, può anche occasionalmente causare problemi quando si modifica una posizione e si impatta in un'altra in modo imprevisto.

Per questo esempio, sembra eccessivo.

    
risposta data 29.11.2018 - 02:44
fonte

Leggi altre domande sui tag