Pergunta

Existe um gerador de números seqüenciais no nível do sistema gerenciado? DateTime.now.ticks não servirá porque as operações que estou fazendo às vezes ocorrem mais de uma vez por tique -taxas.


Requisito esclarecimentos:

  • Processo Agnóstico - Existe realmente apenas um processo que estaria acessando isso.
  • O desempenho é crítico! Isso é usado para registrar impressões em um servidor, que pode atingir 1k/s

Precisaria ser um dos seguintes:

  • Um número seqüencial de 4 bytes que redefine cada tick
  • Um número seqüencial de 12 bytes - essencialmente adicionando 4 bytes de granularidade a um tempo de dados
Foi útil?

Solução

Ninguém que se destina a isso, mas você pode usar System.diagnostics.PerformanCounter. Você também pode usar o registro, mas precisará serializar em serializar acesso de leitura/gravação acumulando os processos.

System.Diagnostics.PerformanceCounter pc 
    = new System.Diagnostics.PerformanceCounter("SeqCounter", "SeqInstance");
long myVal=pc.Increment();

Editar

Quanto mais eu penso sobre isso, acho que essa pode ser uma boa solução. O incremento aumentará o contador em 1 através de uma operação atômica que deve funcionar com todos os processos em um sistema.

Editar

Com base em suas edições, eu não recomendaria usar um contador de desempenho. Um contador de desempenho foi uma maneira de encaixar vários processos. Não tenho certeza de como a implementação interna está codificada.

Por que você não pode simplesmente usar uma variável estática e incrementá -la? Você terá que bloquear algo se quiser que isso seja o ThreadSafe.

System.Threading.Interlocked.Increment

FYI: Se você usar a versão longa em um sistema de 32 bits, ele não será seguro.


Edição para mostrar a implementação que usei (DS):

public static class Int32Sequencer
{
    private static Int32 lastSequence = Int32.MinValue;
    private static Object lockObject = new Object();
    public static Int32 GetNextSequence()
    {
        lock (lockObject)
        {
            unchecked { lastSequence++; }
            return lastSequence;
        }
    }
}

Outras dicas

Um GUID é o mais próximo possível, mas esses são "únicos" e não necessariamente sequenciais. Se você realmente deseja seqüencial em vários processos no nível do sistema, provavelmente terá que rolar o seu próprio.

EDITAR:

OK, então, de seus novos requisitos, vou assumir:

  1. Apenas um processo precisa fazer o trabalho
  2. Você está anexando a um banco de dados

Então aqui está o que eu recomendaria:

  1. Na inicialização do processo, consulte o banco de dados para o último (maior) valor (0 se houver nenhum).
  2. Use um longo e incremento simples para cada linha de dB. Você deseja inserir em lotes devido à sua alta taxa de dados.

Isso deve resolver. Mantenha simples. Isso não tem bloqueios, um leve (insignificante) acerto na inicialização e números seqüenciais no seu banco de dados. Esse algoritmo também é agnótico de processo, desde que você tenha apenas um processo executando-o.

Eu acho que a coisa mais próxima é um GUID, que, como tenho certeza de que você está ciente, é, na melhor das hipóteses, apenas parcialmente seqüencial.

Há um artigo aqui que fornece alguns detalhes para o SQL Server:Guids sequenciais no SQL Server Essa técnica é usada para minimizar as divisões de página devido à aleatoriedade dos GUIDs. Talvez esse link lhe dê algumas dicas ou idéias.

Acho que precisamos saber um pouco mais sobre o que você está procurando. Você pode esclarecer um pouco sua pergunta. Em particular o serviço ...

  • Precisa trabalhar em todos os processos, um processo ou um usuário em particular?
  • Os números devem ser únicos ou apenas seqüenciais?

Com base em sua pergunta, parece haver alguns itens diferentes que você pode estar procurando.

Precisa de um grupo seqüencial de números em todos os processos no sistema

Afaik, não existe esse serviço. Deve -se ser bastante fácil de escrever, mas fazê -lo funcionar em todos os processos é complicado.

Precisa de um grupo seqüencial único de números em todos os processos no sistema

Ligeira variação na primeira pergunta. Esse serviço não existe porque seria impossível implementar. Não há como garantir um número seqüencial exclusivo usando os tipos de dados internos simplesmente porque o valor acabará por transbordar e deixar você com um número duplicado.

Precisa de um método para obter valores únicos no sistema

Como vários outros usuários mencionaram, a melhor opção é uma instância do sistema. Você pode criar um novo usando guid.newguid (). Para quase todos os propósitos, eles podem ser considerados únicos, mas não são seqüenciais.

Eu gosto da opção de banco de dados simplesmente para segurança. Certifique -se de instalar um monstro SQL Server com largura de banda entre seus servidores com memória suficiente. Um sistema semelhante a isso foi implementado na primeira empresa em que trabalhei (antes mesmo de me tornar um programador) e foi muito desonesto. Você pode lutar para escalar isso.

Outra opção seria implementar uma função singleton em seu código ... desde que apenas um domínio do aplicativo o chamasse. Pode ser um pouco mais rápido do que fazer uma viagem de banco de dados. Se, no entanto, você vai registrar essas coisas no banco de dados de qualquer maneira .... que tal combinar os dois ... execute um singleton para velocidade e depois escreva no banco de dados quando os recursos permitirem.

Novamente, se o requisito seqüencial não for tão forte, um GUID seria sua melhor aposta.

Não há como obter uma única série seqüencial sem travar. Não importa qual mecanismo você está usando para atribuir o próximo valor - um contador de desempenho, uma variável estática, o que for - quando dois threads precisam do próximo valor ao mesmo tempo, um deve esperar no outro.

A primeira coisa que eu faço é escrever um programa de teste que gerou um grande número de threads que cada um chamou repetidamente de uma função de incremento de travamento, como o que Daniel Schaffer postou. Isso permitirá que você encontre o limite onde seu aplicativo começa a bater - onde está gastando mais tempo esperando Monitor.Enter do que fazer qualquer outra coisa.

Se isso acaba sendo um problema - e eu aposto que, se os volumes de que você está falando são reais, será - então você deve fazer com que cada thread mantenha seu próprio contador seqüencial, o que você pode fazer marcando o campo do contador com o ThreadStaticAttribute. Em seguida, você pode gerar identificadores exclusivos a partir de uma combinação do ID do encadeamento e do contador.

Essa abordagem não funcionará se você não estiver usando um pool de threads (já que o contador morre quando o thread pertence). E você provavelmente também deseja fazer a contagem de inicialização do aplicativo parte do ID do composto, para não precisar escrever os contadores de threads para armazenamento durável. (Se você não fizesse isso, quando você reiniciou o servidor, os threads começariam a gerar contadores em zero novamente, e se o seu aplicativo criasse um tópico com o mesmo ID que uma instância anterior, você obterá identificadores duplicados.)

Obviamente, isso não é trivial escrever (ou, mais importante, testar), então eu definitivamente recomendo provar que é necessário primeiro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top