Aquí está el código que tengo pero no entiendo qué SemaphoreSlim
está haciendo.
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
List<Task> trackedTasks = new List<Task>();
while (DoMore())
{
await ss.WaitAsync();
trackedTasks.Add(Task.Run(() =>
{
DoPollingThenWorkAsync();
ss.Release();
}));
}
await Task.WhenAll(trackedTasks);
}
void DoPollingThenWorkAsync()
{
var msg = Poll();
if (msg != null)
{
Thread.Sleep(2000); // process the long running CPU-bound job
}
}
¿Qué espera ss.WaitAsync();
y ss.Release();
qué hace?
Supongo que si ejecuto 50 subprocesos a la vez, luego escribo código como, SemaphoreSlim ss = new SemaphoreSlim(10);
entonces se verá obligado a ejecutar 10 subprocesos activos a la vez.
Cuando se completa uno de los 10 subprocesos, comenzará otro subproceso. Si no estoy en lo cierto, ayúdame a comprender la situación de la muestra.
¿Por qué se await
necesita junto con ss.WaitAsync();
? ¿Qué hace ss.WaitAsync();
?
Respuestas:
Eso es correcto; el uso del semáforo asegura que no habrá más de 10 trabajadores haciendo este trabajo al mismo tiempo.
Llamar
WaitAsync
al semáforo produce una tarea que se completará cuando ese hilo tenga "acceso" a ese token.await
Hacer esa tarea permite que el programa continúe la ejecución cuando está "permitido" hacerlo. Tener una versión asincrónica, en lugar de llamarWait
, es importante tanto para garantizar que el método permanezca asincrónico, en lugar de ser síncrono, como para lidiar con el hecho de que unasync
método puede estar ejecutando código en varios subprocesos, debido a las devoluciones de llamada, etc. la afinidad del hilo natural con los semáforos puede ser un problema.Una nota al margen:
DoPollingThenWorkAsync
no debería tener elAsync
sufijo porque en realidad no es asincrónico, es sincrónico. Solo llámaloDoPollingThenWork
. Reducirá la confusión de los lectores.fuente
Thread.Sleep
en el código original devastaría el programador de tareas. Si no es asincrónico con el núcleo, no es asincrónico.En el jardín de infancia a la vuelta de la esquina, usan un SemaphoreSlim para controlar cuántos niños pueden jugar en la sala de educación física.
Pintaron en el suelo, fuera de la habitación, 5 pares de huellas.
Cuando llegan los niños, dejan sus zapatos en un par de huellas libres y entran a la habitación.
Una vez que terminan de jugar, salen, recogen sus zapatos y "liberan" un espacio para otro niño.
Si llega un niño y no quedan huellas, van a jugar a otro lugar o simplemente se quedan un rato y revisan de vez en cuando (es decir, no hay prioridades FIFO).
Cuando una maestra está cerca, ella "suelta" una fila adicional de 5 huellas en el otro lado del pasillo para que 5 niños más puedan jugar en la habitación al mismo tiempo.
También tiene las mismas "trampas" de SemaphoreSlim ...
Si un niño termina de jugar y sale de la habitación sin recoger los zapatos (no activa la "liberación"), la ranura permanece bloqueada, aunque teóricamente haya una ranura vacía. Sin embargo, el niño suele ser regañado.
A veces, uno o dos niños astutos esconden sus zapatos en otro lugar y entran en la habitación, incluso si ya se han tomado todas las huellas (es decir, el SemaphoreSlim no controla "realmente" cuántos niños hay en la habitación).
Esto no suele terminar bien, ya que el hacinamiento de la sala tiende a terminar en niños llorando y el maestro cerrando completamente la sala.
fuente
Aunque acepto que esta pregunta realmente se relaciona con un escenario de bloqueo de cuenta regresiva, pensé que valía la pena compartir este enlace que descubrí para aquellos que deseen usar un SemaphoreSlim como un simple bloqueo asincrónico. Le permite usar la declaración using que podría hacer que la codificación sea más ordenada y segura.
http://www.tomdupont.net/2016/03/how-to-release-semaphore-with-using.html
Yo cambié
_isDisposed=true
y_semaphore.Release()
en su Dispose en caso de que de alguna manera se llamara varias veces.También es importante tener en cuenta que SemaphoreSlim no es un bloqueo reentrante, lo que significa que si el mismo hilo llama a WaitAsync varias veces, el recuento que tiene el semáforo se reduce cada vez. En resumen, SemaphoreSlim no es consciente de los subprocesos.
Con respecto a las preguntas sobre la calidad del código, es mejor poner la versión en un último intento para asegurarse de que siempre se publique.
fuente