Essa é uma pergunta que me foi feita em uma entrevista de emprego e não consigo descobrir a resposta que eles estavam procurando, então espero que alguém aqui possa ter algumas idéias. O objetivo é escrever uma função que é garantida para nunca retornar o mesmo valor duas vezes. Suponha que essa função será acessada por várias máquinas simultaneamente.
Minha ideia era atribuir a cada máquina um ID exclusivo e passar esse valor para a função exclusiva de gerador de valor:
var i = 0;
function uniq(process_id, machine_id) {
return (i += 1).toString() + machine_id + "-" + process_id;
}
Isso evitaria as consequências das condições de corrida, pois, mesmo que dois ou mais processos leiam o mesmo valor i
, cada valor de retorno será marcado como uma combinação exclusiva de identificação do processo e identificação da máquina. No entanto, meu entrevistador não gostou desta resposta, porque colocar outra máquina on-line envolve atribuir um ID a ela.
Então, alguém pode pensar em outra maneira de resolver isso que não envolve a configuração de cada máquina para ter um ID exclusivo? Eu gostaria de ter uma resposta caso essa pergunta surja novamente. Obrigado.
Respostas:
Não seja chique, basta jogar um contador simples (thread-safe) atrás de algum ponto de extremidade de comunicação (WCF, serviço da web, o que for):
Sim, acabará por transbordar. Sim, ele não suporta reinicializações. Sim, não é aleatório. Sim, alguém poderia executar isso em vários servidores.
Essa é a coisa mais simples que satisfaz os requisitos práticos. Em seguida, deixe- os serem os que acompanham esses problemas (para garantir que eles entendam as limitações, eles realmente acham que você precisa de mais de 2 ^ 64 IDs), para que você possa perguntar sobre quais compensações estão bem. Ele precisa sobreviver a reinicializações? E a falha no disco rígido? E a guerra nuclear? Precisa ser aleatório? Quão aleatório?
fonte
x
. E acho que sem uma explicação sobre o tipo de mecanismo de bloqueio que você tem em mente, essa resposta é bastante vaga.System.Threading.Interlocked
classe, que fornece incrementos atômicos. Mas você também pode ler isso como algum tipo de pseudo-código.Se eu fizesse essa pergunta e eles deixassem claro que ela deve ser única nas reinicializações e nas máquinas diferentes, eu daria a eles uma função que chama o mecanismo padrão para criar um novo GUID, seja lá o que acontecer o idioma que está sendo usado.
fonte
O entrevistador disse que o método será chamado simultaneamente, não em paralelo; basta retornar a data / hora para o máximo de casas decimais possível.
Por que todo mundo está pensando demais nisso? Você ficará morto muito tempo antes que qualquer finitude seja gasta e não terá chance de colisão.
Se você estiver preocupado com o retorno da mesma hora, adicione um atraso pelo menor tempo mensurável.
Se você estiver preocupado com a possibilidade de adiar o relógio para o horário de verão (experimentando uma vez duas vezes), adicione uma constante à hora na segunda vez em que o experimentar.
fonte
Primeiro, você deve fazer duas perguntas ao entrevistador.
Questão 1.
se o entrevistador espera que uma ou mais "máquinas centrais" sejam usadas para atribuir alguns números únicos ou blocos de números únicos.
Questão 2.
Se o entrevistador espera um mecanismo para a detecção de colisão, ou aceita o risco calculado de uma chance minúscula de colisão sem detectá-lo explicitamente.
Existe também a abordagem de defesa em profundidade, na qual se incorpora parte do ID do usuário à aleatoriedade (portanto, não inteiramente aleatória). Portanto, a chance de o mesmo usuário encontrar uma colisão no conteúdo criado por esse mesmo usuário é reduzida.
Existe uma pergunta implícita 3, ...
Mas é preciso avaliar a si mesmo sem perguntar, porque é extremamente indelicado perguntar ao seu entrevistador.
Se o entrevistador assume o conhecimento de probabilidade, risco e algumas técnicas simples empregadas em sistemas de criptografia e segurança da informação.
O primeiro tipo de conhecimento garante que você não esteja tentando convencer uma pessoa não científica a aceitar um conceito científico que ela não aceitará.
O segundo tipo de conhecimento garante que você lide com preocupações que são adicionais à mera probabilidade. Em outras palavras, como se defender de "agressores" que desejam intencionalmente interromper seu esquema de randomização, manipulando a (s) máquina (s) ou seus hosts virtuais para forçar duas máquinas a gerar o mesmo valor.
Porque perguntar.
O motivo é que, se o entrevistador espera isso de uma maneira ou de outra, tentar responder com a abordagem oposta nunca fará o entrevistador feliz.
A razão mais profunda é que algumas pessoas não gostam da idéia de dizer, uma
1.0e-20
chance de falhar. (Tentarei não levantar argumentos filosóficos ou religiosos aqui.)Primeiro, o "espaço para nome" dos números aleatórios é transformado em uma hierarquia, com um certo número de bits alocado para uma fonte de randomização e o outro número de bits alocado para outras formas, etc.
A abordagem centralizada conta com alguma autoridade central para atribuir exclusivamente o primeiro nível de bits. Em seguida, as outras máquinas podem preencher o restante dos bits.
Existem várias abordagens descentralizadas:
fonte
Portanto, tendo em mente que essa é uma pergunta de entrevista e não um cenário real da vida real, acredito que a abordagem correta (e provavelmente o que o entrevistador está procurando) é fazer uma pergunta esclarecedora ou escrever "Não pode ser feito "e seguir em frente. Aqui está o porquê.
O que o entrevistador pergunta:
O que o entrevistador precisa:
Nunca assuma.
Quando um engenheiro recebe um requisito (por meio de uma SOW ou Especificação ou algum outro documento de requisitos), alguns são evidentes e outros são totalmente incertos. Este é um exemplo perfeito deste último. Como as respostas anteriores mostraram, não há como responder a esse requisito sem fazer várias suposições principais (a) quanto à natureza da pergunta ou (b) quanto à natureza do sistema, porque o requisito não pode ser atendido. como está escrito (é impossível).
A maioria das respostas faz uma tentativa ou outra de resolver o problema por meio de uma série de suposições. Recomenda-se especificamente fazê-lo rapidamente e deixar o cliente se preocupar se estiver errado.
Esta é realmente uma péssima abordagem. Como cliente, se eu der um requisito claro, e o engenheiro sair e me criar uma solução que não funcione, ficarei chateado que eles tenham ido trabalhar e gastaram meu dinheiro sem se preocupar em me perguntar primeiro. Esse tipo de tomada de decisão descuidada demonstra falta de trabalho em equipe, incapacidade de pensar criticamente e mau julgamento. Pode levar a qualquer tipo de conseqüências negativas, incluindo perda de vida em um sistema crítico de segurança.
Por que fazer a pergunta?
O ponto se este exercício é que é caro e demorado criar requisitos ambíguos. No caso do OP, você recebeu uma tarefa impossível. Sua primeira ação deve ser pedir esclarecimentos - o que é necessário? Que grau de exclusividade é necessário? O que acontece se um valor não for exclusivo? A resposta para essas perguntas pode ser a diferença entre várias semanas e alguns minutos. No mundo real, um dos maiores fatores de custo em sistemas complexos (incluindo muitos sistemas de software) são requisitos pouco claros e pouco compreendidos. Isso leva a erros caros e demorados, redesenhamentos, frustração de clientes e equipes e cobertura da mídia embaraçosa se o projeto for grande o suficiente.
O que acontece quando você assume?
Dada a minha experiência na indústria aeroespacial e devido à natureza altamente visível das falhas aeroespaciais, gosto de trazer exemplos desse domínio para ilustrar pontos importantes. Vamos examinar um par de missões fracassadas em Marte - o Mars Climate Orbiter e o Mars Polar Lander. Ambas as missões falharam devido a problemas de software - porque os engenheiros fizeram suposições inválidas devido, em parte, a requisitos pouco claros e pouco comunicados.
Mars Climate Orbiter - este caso é tipicamente citado como o que acontece quando a NASA tenta converter inglês em unidades métricas. No entanto, essa é uma representação excessivamente simplista e pobre do que realmente aconteceu. É verdade que houve um problema de conversão, mas isso ocorreu devido a requisitos pouco comunicados na fase de design e a um esquema de verificação / validação incorreto. Além disso, quando dois engenheiros diferentes perceberam o problema porque era óbvio a partir dos dados da trajetória de vôo, eles não levaram o problema ao nível adequado porque supuseram que se tratava de um erro de transmissão. Se a equipe de operações da missão estivesse ciente do problema, havia tempo suficiente para corrigi-lo e salvar a missão. Nesse caso, havia uma condição lógica impossível que não era reconhecida pelo que era, levando a dispendiosas falhas na missão.
Mars Polar Lander- este caso é um pouco menos conhecido, mas possivelmente mais embaraçoso devido à sua proximidade temporal à falha do Mars Climate Orbiter. Nesta missão, o software controlava a descida do foguete assistida pelo propulsor na superfície marciana. Em um ponto a 40 metros acima da superfície, as pernas do veículo pousaram em preparação para o pouso. Havia também um sensor nas pernas que detectava movimento (para sinalizar quando foram afetados) para dizer ao software para desligar o motor. O melhor palpite da NASA sobre o que aconteceu (porque existem várias falhas possíveis e dados incompletos) é que vibrações aleatórias nas pernas devido à sua implantação simultânea e indevidamente acionaram o mecanismo de desligamento 40m acima da superfície, resultando no acidente e na destruição dos US $ 110 Nave espacial M. Essa possibilidade foi levantada no desenvolvimento, mas nunca foi abordado. Por fim, a equipe de software fez suposições inválidas sobre como esse código precisava ser executado (uma dessas suposições é que um sinal espúrio teria vida curta demais para ser captado, apesar dos testes mostrarem o contrário), e essas suposições nunca foram questionadas até depois o fato.
Considerações adicionais
Entrevistar e avaliar pessoas é um negócio complicado. Existem várias dimensões de um candidato que um entrevistador pode querer explorar, mas uma das mais importantes é a capacidade de um indivíduo de pensar criticamente. Por várias razões, entre as quais o pensamento crítico é mal definido, temos dificuldade em avaliar as habilidades de pensamento crítico.
Como instrutor de engenharia, uma das minhas maneiras favoritas de avaliar a capacidade de um aluno de pensar criticamente era fazer uma pergunta um tanto ambígua. Os alunos mais aguçados entendiam a premissa defeituosa da pergunta, observavam-na e respondiam, dada a premissa, ou se recusavam a responder por completo. Normalmente, eu faria uma pergunta semelhante à seguinte:
(A propósito, você ficaria chocado com a frequência com que uma especificação tão ruim aparece no local de trabalho.)
Espero que os alunos reconheçam que não é possível criar um recurso perfeito e que eles declarem isso em sua resposta. Normalmente, eu atribuiria um ponto de bônus se eles disserem que voltarão ao designer e pedirão esclarecimentos antes de fazer a peça. Se um aluno começar a me dizer como alcançará a planaridade 0,001 ou algum outro valor compensado, concedo zero pontos. Isso me ajuda a mostrar aos meus alunos que eles precisam pensar no quadro geral.
Bottom Line
Se estou entrevistando um engenheiro (ou profissão similar), procuro alguém que possa pensar criticamente e questionar o que foi colocado na sua frente. Quero alguém que faça a pergunta "Isso faz sentido?" .
Não faz sentido pedir uma peça perfeitamente plana, porque não existe algo perfeito. Não faz sentido solicitar uma função que nunca retorne um valor duplicado, porque é impossível fazer essa garantia. Na programação, geralmente ouvimos a frase "lixo dentro, lixo fora". Se você recebe lixo para requisitos, é sua responsabilidade ética parar e fazer qualquer pergunta que o ajude a obter a verdadeira intenção. Se eu estiver entrevistando um candidato e lhes der um requisito incerto, esperarei perguntas de esclarecimento.
fonte
Garantir a exclusividade é difícil, porque os computadores não possuem variáveis infinitamente grandes. Nenhuma máquina Turing do mundo real pode.
A meu ver, existem dois problemas aqui, e ambos têm soluções bem estabelecidas.
Aqui está a minha solução em Java:
BigInteger é um tipo inteiro de tamanho arbitrário. Pode crescer para manter valores muito grandes, mesmo que não sejam infinitos. O bloqueio garante simultaneidade, portanto, o mesmo valor não pode ser retornado duas vezes por duas solicitações simultâneas atendidas por threads separados.
fonte
Eu exporia a função através de uma porta no servidor; Para chamar a função, a máquina solicitante solicita uma conexão e recebe uma, enquanto ao mesmo tempo recebe um código de identificação (número sequencial por simplicidade). Sempre que uma mensagem é enviada para a porta solicitando o valor exclusivo, o valor é gerado concatenando o hash MD5 da data e hora atuais com o hash MD5 do código de identificação.
Se eles querem uma solução mais à prova de balas, teriam que especificar seus requisitos reais, em vez de serem todos vagos sobre as coisas.
fonte
Da maneira acima, podemos garantir que o valor de retorno seja diferente, mesmo se houver reinicialização ou mesmo se for chamado simultaneamente de máquinas diferentes.
fonte