Existe uma maneira melhor de acelerar um trabalho de alto rendimento?

Eu criei uma class simples que mostra o que estou tentando fazer sem nenhum ruído. Sinta-se à vontade para bater no meu código. É por isso que postei aqui.

public class Throttled : IDisposable { private readonly Action work; private readonly Func stop; private readonly ManualResetEvent continueProcessing; private readonly Timer throttleTimer; private readonly int throttlePeriod; private readonly int throttleLimit; private int totalProcessed; public Throttled(Action work, Func stop, int throttlePeriod, int throttleLimit) { this.work = work; this.stop = stop; this.throttlePeriod = throttlePeriod; this.throttleLimit = throttleLimit; continueProcessing = new ManualResetEvent(true); throttleTimer = new Timer(ThrottleUpdate, null, throttlePeriod, throttlePeriod); } public void Dispose() { throttleTimer.Dispose(); ((IDisposable)continueProcessing).Dispose(); } public void Execute() { while (!stop()) { if (Interlocked.Increment(ref totalProcessed) > throttleLimit) { lock (continueProcessing) { continueProcessing.Reset(); } if (!continueProcessing.WaitOne(throttlePeriod)) { throw new TimeoutException(); } } work(); } } private void ThrottleUpdate(object state) { Interlocked.Exchange(ref totalProcessed, 0); lock (continueProcessing) { continueProcessing.Set(); } } } 

Código mais recente

 public class Throttled { private readonly Func work; private readonly ThrottleSettings settings; private readonly Stopwatch stopwatch; private int totalProcessed; public Throttled(Func work, ThrottleSettings settings) { this.work = work; this.settings = settings; stopwatch = new Stopwatch(); } private void Execute() { stopwatch.Start(); while (work()) { if (++totalProcessed > settings.Limit) { var timeLeft = (int)(settings.Period - stopwatch.ElapsedMilliseconds); if (timeLeft > 0) { Thread.Sleep(timeLeft); } totalProcessed = 0; stopwatch.Reset(); stopwatch.Start(); } } } } 

Primeiro de tudo, eu iria me livrar completamente do thread de controle, porque o seu trabalho pode ser feito facilmente antes de chamar para o work() .

Então, eu faria o thread de trabalho para ser diferente do segmento principal, desbloqueando assim o thread principal para outras tarefas. Em seguida, adicionaria uma function para cancelar o processamento, o que talvez configurasse um sinalizador para verificar o encadeamento de trabalho.

Editar:
De acordo com os comentários, nosso objective é limitar o número de chamadas de work() durante cada ticks do throttlePeriod . Podemos fazer melhor anotando o tempo em um cronômetro, comparando-o após as operações de trabalho throttleLimit e dormindo o tempo restante. Desta forma, novamente, não precisamos de um thread de timer.

Editar: (removido, estava incorreto)
Editar:
Podemos fazer até mesmo algum tipo de equilíbrio: estando dentro de um período de throttlePeriod , calculamos quanto tempo o work() levou, para que possamos estimar o tempo que todo o work() restante work() vai demorar e esperar entre cada um deles. work() s uma parte igual do tempo restante. Isso nos fará não executar todo o work() muito rápido no início do período alocado, possivelmente bloqueando o DB.

Por que acelerar? e por que dormir () quando você pode colocar um segmento em uma prioridade mais baixa e tê-lo absorver todos os ciclos de CPU não utilizados, realizando seu trabalho o mais rápido possível sem interromper qualquer trabalho de prioridade mais alta?

Na verdade, por que não colocar todos os threads que não são da interface do usuário em uma prioridade de thread inferior para que seu aplicativo permaneça responsivo em geral?

A única ressalva aqui é que, se você estiver fazendo E / S, o access ao disco precisa ser acelerado para manter todo o resto funcionando sem problemas.