c# - startnew - Necesidad de entender el uso de SemaphoreSlim
task start() c# (2)
Aquí está el código que tengo pero no entiendo qué está haciendo SemaphoreSlim.
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(); & ss.Release();
ss.WaitAsync(); & ss.Release();
¿hacer?
Supongo que si ejecuto 50 subprocesos a la vez, escribo código como SemaphoreSlim ss = new SemaphoreSlim(10);
entonces será forzado a ejecutar 10 hilos activos a la vez.
Cuando se complete uno de los 10 hilos, se iniciará otro hilo ... si no estoy en lo cierto, ayúdeme a comprender la situación de muestra.
¿Por qué se necesita esperar para usar junto con ss.WaitAsync();
? ¿Qué hace ss.WaitAsync();
¿hacer?
Supongo que si ejecuto 50 subprocesos a la vez, código como SemaphoreSlim ss = new SemaphoreSlim (10); forzará a correr 10 hilos activos a la vez
Eso es correcto; el uso del semáforo asegura que no habrá más de 10 trabajadores haciendo este trabajo al mismo tiempo.
Llamar a WaitAsync
en el semáforo produce una tarea que se completará cuando ese hilo haya recibido "acceso" a ese token. await
esa tarea, el programa puede continuar su ejecución cuando se le "permita" hacerlo. Tener una versión asíncrona, en lugar de llamar a Wait
, es importante tanto para garantizar que el método permanezca asíncrono, en lugar de ser sincrónico, como para el hecho de que un método async
puede ejecutar código en varios subprocesos, debido a las devoluciones de llamada, y así, la afinidad del hilo natural con los semáforos puede ser un problema.
Una nota al DoPollingThenWorkAsync
: DoPollingThenWorkAsync
no debería tener el postfix Async
porque en realidad no es asíncrono, es síncrono. Solo llámalo DoPollingThenWork
. Se reducirá la confusión para los lectores.
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 SemaphoreSlim como un simple bloqueo asíncrono. Le permite utilizar la instrucción using que podría hacer que la codificación sea más limpia y segura.
http://www.tomdupont.net/2016/03/how-to-release-semaphore-with-using.html
Hice el intercambio _isDisposed=true
y _semaphore.Release()
alrededor de su Disposición, aunque en caso de que de alguna manera fuera llamado varias veces.