2008-11-19 20 views
10

Tenemos una aplicación que genera datos simulados para uno de nuestros servicios con fines de prueba. Cada elemento de datos tiene un Guid único. Sin embargo, cuando ejecutamos una prueba después de algunos cambios de código menores en el simulador, todos los objetos generados por él tenían la misma Guid.Duplicado devuelto por Guid.NewGuid()?

Se creó un único objeto de datos, luego un bucle for donde se modificaron las propiedades del objeto, incluido un nuevo Guid único, y se envió al servicio mediante comunicación remota (serializable, no marshal-by-ref, si eso es lo que estás pensando), haz un bucle y hazlo de nuevo, etc.

Si ponemos un pequeño Thread.Sleep (...) dentro del bucle, generó id únicos. Sin embargo, creo que es un acertijo. Creé una aplicación de prueba que acaba de crear un guid tras otro y no obtuvo un solo duplicado.

Mi teoría es que el IL fue optimizado de una manera que causó este comportamiento. Pero lo suficiente sobre mis teorías. ¿Qué piensas? Estoy abierto a sugerencias y formas de probarlo.

ACTUALIZACIÓN: Parece haber mucha confusión acerca de mi pregunta, así que déjenme aclarar. NO creo que NewGuid() esté roto. Claramente funciona ¡Está bien! Sin embargo, hay un error en alguna parte, que hace que NewGuid(): 1) se invoque solo una vez en mi ciclo 2) se llame cada vez en mi ciclo pero se me asigna una sola vez 3) algo más que no he pensado

Este error puede estar en mi código (MÁS probable) o en algún lugar de optimización.

Para reiterar mi pregunta, ¿cómo debo depurar este escenario?

(y gracias por la gran discusión, esto es realmente ayudar a aclarar el problema en mi mente)

ACTUALIZACIÓN # 2: Me gustaría poder escribir un ejemplo que muestra el problema, pero eso es parte de mi problema. No puedo duplicarlo fuera de todo el conjunto de aplicaciones (cliente y servidores).

He aquí un fragmento relevante sin embargo:

OrderTicket ticket = new OrderTicket(...); 

for(int i = 0; i < _numOrders; i++) 
{ 
    ticket.CacheId = Guid.NewGuid(); 
    Submit(ticket); // note that this simply makes a remoting call 
} 
+0

Si cree que hay un error en la IL, use Reflector para rastrearlo. –

+0

Ah, sí. Pensé en eso. Pero mi suposición inicial fue que probablemente estaría en el optimizador JIT. No se puede usar Reflector para eso. – dviljoen

+0

Si no crees que sea un error de NewGuid, publica un código que muestre el problema.O, al menos, publique el código que * tuvo * el problema. Además, responda la pregunta de si eliminar Thread.Sleep hace que el problema vuelva a aparecer. Soy bastante bueno en depuración psíquica, pero aún mejor con algunos detalles. –

Respuesta

21

Hace Enviar hacer una llamada asíncrona, o el objeto de ticket va a otro hilo en cualquier etapa.

En el ejemplo del código está reutilizando el mismo objeto. ¿Qué pasa si Enviar envía el ticket en un hilo de fondo después de un breve retraso (y no toma una copia). Cuando cambia el CacheId, en realidad está actualizando todos los envíos pendientes. Esto también explica por qué un Thread.Sleep soluciona el problema. Prueba esto:

for(int i = 0; i < _numOrders; i++) 
{ 
    OrderTicket ticket = new OrderTicket(...); 
    ticket.CacheId = Guid.NewGuid(); 
    Submit(ticket); // note that this simply makes a remoting call 
} 

Si por alguna razón esto no es posible, probar esto y ver si siguen siendo los mismos:

ticket.CacheId = new Guid("00000000-0000-0000-0000-" + 
    string.Format("{0:000000000000}", i)); 
+0

¡Lo tienes! Ese es precisamente el problema. ¡¡¡Increíble!!! Gracias. – dviljoen

+3

@dviljoen: parece que ganaría esa apuesta después de todo. :) – MusiGenesis

3

Es un error en el código. Si ha logrado generar múltiples guid es la explicación más probable. La pista está aquí en su pregunta: "cuando nos encontramos con una prueba después de algunos cambios de código menores en el simulador de todos los objetos generados por ella tenían el mismo GUID"

+0

Sí, eso es lo que pensé también. Pero no pude encontrarlo Cada iteración llamaba a NewGuid() cada vez y cada vez que devolvía el mismo Id. Sugerencias? – dviljoen

+0

Ese es el problema con los generadores de números aleatorios, nunca se puede estar seguro. – tsilb

+0

No compro eso. El guid tiene algo de aleatorio, y sí, los duplicados teóricos son "posibles" pero no TODOS. Claramente este no es el problema aquí. Hubo algo mal con nuestro código o el optimizador. Mi problema es que no sé cómo averiguar cuál. Sugerencias? – dviljoen

2

ver este article acerca de cómo se crea un GUID.

Este artcile vino de This respuesta.

En la línea inferior si está creando los GUID demasiado rápido y el reloj no se ha movido hacia delante es por eso que está obteniendo algunos iguales. Sin embargo, cuando pones un sueño funciona porque el reloj se ha movido.

+0

Gracias, pero de nuevo, esto no me ayuda. Sé que un Guid es estadísticamente único. Mi problema NO es que tuviera 2 de 10 000 Guids que eran incautos. Mi problema fue que 10,000 de 10,000 fueron engañados. Eso no es una colisión estadística. Eso es un error. ¿Pero donde? ¿Y cómo encontrarlo? – dviljoen

+0

Lo siento, tuve que votar por no leer completamente el artículo al que se vinculaba. – MusiGenesis

2

El código en el trámite y OrderTicket sería útil también ...

Usted está reutilizando OrderTicket. Sospecho que usted (o remoting) está llamando por lotes, probablemente con respecto a # de conexiones/límites de host, y recogiendo el último valor de CacheId cuando finalmente los envía.

Si depura o subprocesos.Duerme la aplicación, estás cambiando el tiempo para que la llamada remota finalice antes de asignar un nuevo CacheId.

¿Estás sincronizando la llamada remota? Pensaría que una llamada de sincronización bloquearía, pero lo verificaría con un analizador de paquetes como Wireshark para estar seguro. A pesar de todo, simplemente cambiar para crear un nuevo OrderTicket en cada iteración probablemente sea el truco.

Editar: La pregunta es no sobre NewGuid está roto ... así que mi respuesta anterior ha sido eliminada.

+0

Sé que es un error. Pero como muchos otros aquí, parece que se está fijando en la singularidad de un Guid. Ese no es el problema. Nuevamente, 2 engaños de cada 10,000 serían un problema de exclusividad. Obtendré 10.000 de la misma Guid exacta. – dviljoen

+0

Si sabe que es un error (lo que significa que cree que es un error de la aplicación), ¿por qué el título "Duplicate returned by Guid.NewGuid()" y la teoría de que es el optimizador de JIT el que causa un problema? –

+0

En cuanto a As fijarse en la "singularidad de un Guid", eso no es ni cerca de lo que estaba postulando. Una salida de entropía o malloc no capturado no detectado (por ejemplo) podría causar todo tipo de problemas, incluidas las repetidas Guids (potencialmente, una vez más, es una teoría descabellada para su selección es una mentalidad rota). –

6

Miles de desarrolladores usan Guids en .NET. Si Guid.NewGuid() tuviera alguna tendencia a "atascarse" en un valor, el problema se habría encontrado hace mucho tiempo.

Los pequeños cambios de código son el culpable seguro aquí. El hecho de que Thread.Sleep (que es menos un arenque rojo que un pez que se pudre al sol) "corrige" su problema sugiere que sus propiedades se configuran de una manera extraña que no puede tener efecto hasta que el ciclo deje de bloquear (ya sea terminando o por Thread.Sleep). Incluso estaría dispuesto a apostar que el "cambio menor" era restablecer todas las propiedades de un hilo separado.

Si publicó un código de muestra, eso ayudaría.

+1

Perderías esa apuesta. Este es un hilo único que simplemente genera datos de objetos a través del cable. – dviljoen

+0

Vamos, publica un código. Guid.NewGuid() no es el problema. – MusiGenesis

+0

Bien, te voté porque, sí, estaría pagando. ;-) – dviljoen

1

No conozco los detalles de cómo se generan los GUID .. todavía. Sin embargo, actualmente mi org. está criando GUID a un ritmo que avergonzaría a los conejos. Así que puedo responder por el hecho de que los GUID no están rotos ... aún.

  • Publique el código fuente si es posible .. o una aplicación de reproducción de clones. Muchas veces creo que el acto de crear esa aplicación de clonación para reproducir el problema me muestra el problema.
  • El otro enfoque sería comentar "esos pequeños cambios". Si eso soluciona el problema, puede triangularizar para encontrar la línea ofensiva de código. Eye-ball el menor cambia drásticamente ... quiero decir real Duro.

Háganos saber cómo va ... esto suena interesante.

+0

Estaría en graves problemas profesionales si Guid.NewGuid() escupe a un tonto cada pocos millones de llamadas, y mucho menos cada vez. – MusiGenesis

0

Mi instinto me dice algo en este sentido que está pasando. ..

class OrderTicket 
{ 
    Guid CacheId {set {_guid = new Guid("00000000-0000-0000-0000-");} 
} 

registrar el valor de CacheId en un archivo de registro cada vez que su llamada con un seguimiento de la pila ... Tal vez alguien se está estableciendo.

+0

No. Simplemente ajusta _cacheId que se inicializa en Guid.NewGuid() – dviljoen

+0

¿Qué sucede cuando registra el valor + el trazo de pila de System.diagnostics ... –

Cuestiones relacionadas