2016-01-08 4 views
6

Qualcuno sa se è costoso per ExecutionContext.Capture() e per ?Costo di ExecutionContext.Capture() e ExecutionContext.Run (contesto, lavoro, stato)

Fa diminuire le prestazioni e quindi si consiglia di usare con attenzione?

Mi chiedo poiché ho un oggetto ContextItem in cui salvo il contesto lavoro e lo stato in per eseguirlo in seguito. Dal momento che voglio essere in grado di reagire a un'eccezione che potrebbe essere generata durante l'esecuzione del lavoro, ho un fallback che viene eseguito se viene lanciata un'eccezione nel lavoro. E ho anche il lavoro finale, che viene eseguito in ogni caso a prescindere dal fatto che sia stata lanciata o meno un'eccezione. Dal momento che posso usare ExecutionContext solo una volta dovrei ExecutionContext.Capture() tre volte per uno di questi ContextItem ...

Oppure questo suona come un approccio totalmente sbagliato?

+3

Beh, un downvote senza un commento non è affatto utile ... – fosb

+3

@cory nelson quindi se posso risolvere il problema con un blocco, è economico? Onestamente penso che non sia giusto dire che una domanda non è buona, dal momento che nessuna delle domande per Executiocontext su StackOverflow sta discutendo se è costoso utilizzarla, né le pagine online che ho trovato per questo argomento. Quindi tu dici se non so qualcosa o non capisco una spiegazione che non dovrei fare una domanda? Allora dove è il senso di questo sito? – fosb

+1

Il codice postato è tutto ciò di cui hai bisogno. Fai un giro attorno ad esso con 10 milioni di iterazioni e dai un'occhiata a te stesso. Se il costo è ok, dipende se lo chiami così spesso da diventare un problema. –

risposta

1

Come raccomandato dal @Alois Kraus ho eseguito un test con il seguente codice a confronto blocco per catturare & allineati excecution:

class Program 
{ 
    private static readonly object _lock = new object(); 
    private static readonly int numberOfItems = 1000000; 
    private static readonly int _numberOfIterations = 1000000; 

    private static void Main(string[] args) 
    { 
     MeasureTimeWithLocking(); 
     MeasureTimeWithCapuringContext(); 
     Console.WriteLine(); 
     MeasureTimeWithLocking(); 
     MeasureTimeWithCapuringContext(); 
     Console.WriteLine(); 
     MeasureTimeWithLocking(); 
     MeasureTimeWithCapuringContext(); 
     Console.ReadKey(); 
    } 

    private static void MeasureTimeWithLocking() 
    { 
     List<ContextItem> items = new List<ContextItem>(); 
     Stopwatch stopwatch = Stopwatch.StartNew(); 
     for (int i = 0; i < numberOfItems; i++) 
     { 
      ContextItem item = new ContextItem(); 
      item.Work1 = DoSomeWorkWithLock; 
      item.Work2 = DoSomeWorkWithLock; 
      item.Work3 = DoSomeWorkWithLock; 
     } 

     Parallel.ForEach(items, (item) => 
     { 
      item.Work1(null); 
      item.Work2(null); 
      item.Work3(null); 
     }); 
     stopwatch.Stop(); 
     Console.WriteLine("Time elapsed with locking:   " + stopwatch.Elapsed); 
    } 

    private static void MeasureTimeWithCapuringContext() 
    { 
     List<ContextItem> items = new List<ContextItem>(); 
     Stopwatch stopwatch = Stopwatch.StartNew(); 
     for (int i = 0; i < numberOfItems; i++) 
     { 
      ContextItem item = new ContextItem(); 
      item.Context1 = ExecutionContext.Capture(); 
      item.Context2 = ExecutionContext.Capture(); 
      item.Context3 = ExecutionContext.Capture(); 
      item.Work1 = DoSomeWork; 
      item.Work2 = DoSomeWork; 
      item.Work3 = DoSomeWork; 
     } 

     foreach (ContextItem item in items) 
     { 
      ExecutionContext.Run(item.Context1, item.Work1, null); 
      ExecutionContext.Run(item.Context2, item.Work2, null); 
      ExecutionContext.Run(item.Context3, item.Work3, null); 
     } 
     stopwatch.Stop(); 
     Console.WriteLine("Time elapsed with capturing context: " + stopwatch.Elapsed); 
    } 

    private static void DoSomeWork(object ignored) 
    { 
     Work(); 
    } 


    private static void DoSomeWorkWithLock(object ignored) 
    { 
     lock (_lock) 
     { 
      Work(); 
     } 
    } 

    private static void Work() 
    { 
     int count = 0; 
     for (int i = 0; i < _numberOfIterations; i++) 
     { 
      count ++; 
     } 
    } 

    private class ContextItem 
    { 
     public ExecutionContext Context1 { get; set; } 
     public ExecutionContext Context2 { get; set; } 
     public ExecutionContext Context3 { get; set; } 

     public ContextCallback Work1 { get; set; } 
     public ContextCallback Work2 { get; set; } 
     public ContextCallback Work3 { get; set; } 
    } 
} 

I risultati sono:

enter image description here

Quindi, se ho fatto questo diritto, catturare l'esecuzione di & è in media circa 5 volte più costoso del blocco.

Per rispondere anche la parte della mia domanda:

O Questo suona come un approccio totalmente sbagliato?

ho letto in this article che

se si deve sapere che sono lì, o si sta facendo qualcosa di super avanzato, o qualcosa è andato storto.

L'articolo è stato consigliato su SO come la migliore fonte se si desidera conoscere ExecutionContext. Dopo averlo esaminato ed eseguito alcuni test con un collega mi sono reso conto che stavo usando ExecutionContext dove non aveva senso, in più è meno performante rispetto ai lock e quindi probabilmente è anche meno performante di altre funzionalità/costrutti di threading.

Problemi correlati