Explicación de texto en la que rosca en “C # 3.0 en una cáscara de nuez”
-
22-09-2019 - |
Pregunta
Durante la lectura de C # 3.0 en una cáscara de nuez por Joseph y Ben Albahari , me encontré con el siguiente párrafo (página 673, párrafo primero, en sección titulada " señalización con Esperar y pulso ")
"La monitor clase proporciona otra construcción de señalización a través de dos métodos estáticos, Espera y pulso . El principio es que podemos escribir la lógica de señalización usted mismo usando banderas y campos personalizados (encerrado en bloqueo declaraciones), y luego introducir Espera y pulso comandos a hilar CPU mitigar. La ventaja de este enfoque de bajo nivel es que con sólo Espera , pulso y bloqueo declaración, se puede lograr la funcionalidad de AutoResetEvent , ManualResetEvent y semáforo , así como WaitHandle 's métodos estáticos WaitAll y WaitAny . Por otra parte, Espera y pulso pueden ser susceptibles en situaciones en las todos los mangos son de espera parsimonia desafiado ".
Mi pregunta es, ¿cuál es la interpretación correcta de la última frase?
- Una situación con un gran número decente / de las manijas de espera donde WaitOne () sólo se le llama de vez en cuando en cualquier mango de espera en particular.
- Una situación con un gran número decente / de las manijas de espera, donde rara vez lo hace más de un hilo tienden a bloquear en cualquier mango de espera en particular.
- Algunos otra interpretación.
Le agradeceremos que iluminan ejemplos de este tipo de situaciones y quizás la forma y / o por la que se manejan de manera más eficiente a través de espera y el pulso más que por otros métodos.
Gracias!
Edit: He encontrado el texto online aquí
Solución
Lo que esto quiere decir es que hay algunas situaciones en las Esperar y pulso proporciona una solución más simple que las manijas de espera. En general, esto ocurre cuando:
- El camarero, en lugar de al notificador, decide cuándo Desbloquear
- La condición de bloqueo implica algo más que una simple bandera (quizás varias variables)
Puede seguir utilizando las manijas de espera en estas situaciones, pero Espera / pulso tiende a ser más simple. Lo bueno de Espera / pulso es que esperan libera el bloqueo subyacente a la espera. Por ejemplo, en el siguiente ejemplo, estamos _x e _y la lectura dentro de la seguridad de una cerradura - y sin embargo, que el bloqueo se libera a la espera para que otro hilo puede actualizar esas variables:
lock (_locker)
{
while (_x < 10 && _y < 20) Monitor.Wait (_locker);
}
Otro hilo puede entonces actualizar _x y _y atómicamente (en virtud de la cerradura) y después del pulso para señalar el camarero:
lock (_locker)
{
_x = 20;
_y = 30;
Monitor.Pulse (_locker);
}
La desventaja de Espera / Pulso es que es más fácil de hacerlo mal y cometer un error (por ejemplo, mediante la actualización de una variable y olvidarse de pulso). En situaciones en las que un programa con asas espera es igualmente simple a un programa con Espera / Pulso, recomiendo ir con asas de espera por esa razón.
En términos de consumo / eficiencia de recursos (que creo que estaba aludiendo a), Espera / pulso es generalmente más rápido y más ligero (ya que tiene una aplicación administrada). Esto no suele ser un gran problema en la práctica, sin embargo. Y en ese momento, Framework 4.0 incluye versiones de baja sobrecarga que gestiona de ManualResetEvent y semáforo (ManualResetEventSlim y SemaphoreSlim).
Framework 4.0 también ofrece muchas más opciones de sincronización que disminuye la necesidad de Espera / Pulso:
- CountdownEvent
- Barrera
- PLINQ / Paralelismo de datos (AsParallel, Parallel.Invoke, Parallel.For, Parallel.ForEach)
- Tareas y continuaciones
Todos éstos son mucho más altos niveles de esperar / pulso y la OMI son preferibles para escribir código fiable y fácil de mantener (suponiendo que va a resolver la tarea en cuestión).