Abaixo está uma implementação de um método intertravado baseado em Interlocked.CompareExchange
.
É aconselhável que esse código use uma SpinWait
rotação antes de reiterar?
public static bool AddIfLessThan(ref int location, int value, int comparison)
{
int currentValue;
do
{
currentValue = location; // Read the current value
if (currentValue >= comparison) return false; // If "less than comparison" is NOT satisfied, return false
}
// Set to currentValue+value, iff still on currentValue; reiterate if not assigned
while (Interlocked.CompareExchange(ref location, currentValue + value, currentValue) != currentValue);
return true; // Assigned, so return true
}
Eu já vi SpinWait
usado nesse cenário, mas minha teoria é que deveria ser desnecessário. Afinal, o loop contém apenas algumas instruções e sempre há um thread em progresso.
Digamos que dois threads estejam correndo para executar esse método, e o primeiro thread seja bem-sucedido imediatamente, enquanto o segundo thread inicialmente não faz alterações e precisa reiterar. Sem outros concorrentes, é possível que o segundo thread falhe em sua segunda tentativa ?
Se o segundo thread do exemplo não puder falhar na segunda tentativa, o que podemos ganhar com a SpinWait
? Eliminando alguns ciclos no caso improvável de centenas de threads correrem para executar o método?
SpinOnce
para impedir que um sistema operacional de thread único passe fome. Veja stackoverflow.com/questions/37799381/…Interlocked
. Para esclarecimento, estou interessado apenas em saber se umSpinWait
é significativo ou não , por exemplo, para salvar significativamente os ciclos da CPU ou (obrigado @MatthewWatson!) Impedir que um sistema operacional de thread único passe fome.SpinWait
isso não reduza o consumo de energia, pois o mesmo número de tentativas será realizado de qualquer maneira! (Com dois segmentos, que é uma tentativa para o primeiro e dois para o segundo segmento.)Respostas:
Minha opinião de não especialista é que, nesse caso em particular, onde duas threads ocasionalmente chamam
AddIfLessThan
, aSpinWait
é desnecessário. Pode ser benéfico se os dois threads estiverem chamandoAddIfLessThan
em um loop apertado, para que cada thread possa progredir ininterruptamente por alguns μs.Na verdade, fiz um experimento e medi o desempenho de um thread chamando
AddIfLessThan
em um loop apertado versus dois threads. Os dois threads precisam quase quatro vezes mais para criar o mesmo número de loops (cumulativamente). A adição deSpinWait
a à mistura torna os dois segmentos apenas um pouco mais lentos que o único.fonte
SpinWait
dentro doAddIfLessThan
método e, embora seja um tipo de valor e seuSpinOnce
método nunca seja chamado, ele ainda adiciona alguma sobrecarga.Dois tópicos simplesmente não são um assunto para
SpinWait
discussão. Mas esse código não nos diz quantos threads realmente podem competir pelo recurso e, com um número relativamente alto de threads, o uso doSpinWait
pode se tornar benéfico. Em particular, com um número maior de encadeamentos, a fila virtual de encadeamentos, que está tentando adquirir o recurso com sucesso, fica mais longa e os encadeamentos que são servidos no final têm boas chances de exceder seu intervalo de tempo alocado pelo agendador que, por sua vez, pode levar a um maior consumo de CPU e pode afetar a execução de outros encadeamentos agendados, mesmo com maior prioridade. oSpinWait
tem uma boa resposta para essa situação, definindo um limite superior de rotações permitidas, após o qual a alternância de contexto será executada. Portanto, é uma troca razoável entre a necessidade de fazer uma chamada cara do sistema, a fim de acionar uma alternância de contexto e um consumo descontrolado de CPU do modo de usuário que corre o risco de afetar a execução de outros threads em determinadas situações.fonte
SpinWait
causasse um exagero ou não?SpinWait
estratégia é melhor (com custo relativamente pequeno de dezenas de microssegundos) do que não usá-lo, a menos que você exclua antecipadamente a possibilidade de cenários de alta carga baixa, portanto, encontre um ponto de carga no qual o rendimento possa ser afetado forneceria uma dica, se você precisa ou não (observe que isso também pode depender do número de núcleos).SpinWait
agregação de valor. Até agora, esses parecem ser (A) o caso de núcleo único e (B) possivelmente o caso de contenção muito alta.