Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regarding the usage of SemaphoreSlim with Async/Await

I am not an advanced developer. I'm just trying to get a hold on the task library and just googling. I've never used the class SemaphoreSlim so I would like to know what it does. Here I present code where SemaphoreSlim is used with async & await but which I do not understand. Could someone help me to understand the code below.

1st set of code

await WorkerMainAsync();

async Task WorkerMainAsync()
{
    SemaphoreSlim ss = new SemaphoreSlim(10);
    while (true)
    {
        await ss.WaitAsync();
        // you should probably store this task somewhere and then await it
        var task = DoPollingThenWorkAsync();
    }
}

async Task DoPollingThenWorkAsync(SemaphoreSlim semaphore)
{
    var msg = Poll();
    if (msg != null)
    {
        await Task.Delay(3000); // process the I/O-bound job
    }

    // this assumes you don't have to worry about exceptions
    // otherwise consider try-finally
    semaphore.Release();
}

Firstly, the WorkerMainAsync will be called and a SemaphoreSlim is used. Why is 10 passed to the constructor of SemaphoreSlim?

When does the control come out of the while loop again?

What does ss.WaitAsync(); do?

The DoPollingThenWorkAsync() function is expecting a SemaphoreSlim but is not passed anything when it is called. Is this typo?

Why is await Task.Delay(3000); used?

They could simply use Task.Delay(3000) but why do they use await here instead?

2nd set of code for same purpose

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
    }
}

Here is a task & ss.Release added to a list. I really do not understand how tasks can run after adding to a list?

trackedTasks.Add(Task.Run(async () => 
{
    await DoPollingThenWorkAsync();
    ss.Release();
}));

I am looking forward for a good explanation & help to understand the two sets of code. Thanks

like image 455
Thomas Avatar asked Nov 15 '13 10:11

Thomas


People also ask

What does SemaphoreSlim do?

You can use it as a local semaphore only. The SemaphoreSlim class is the recommended semaphore for synchronization within a single app. A lightweight semaphore controls access to a pool of resources that is local to your application.

What is use of async and await in C# with example?

async/await is single thread event based model. Which allows you to run code out-of-order until the line of code await. In Raku it would actually wait at the await . sub example { my $p = do-something-async; say 'next line'; await $p; say 'done awaiting'}; sub do-something-async { return Promise.in(5).

Why we use async and await in .NET core?

When we don't want to return a result from our async method, we should always return a Task. To validate our asynchronous operations, we have to use the await keyword while calling that operation. When we convert our synchronous code to asynchronous, we have to use the async and await keywords all the way up the chain.

Does async await use thread pool?

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.


1 Answers

why 10 is passing to SemaphoreSlim constructor.

They are using SemaphoreSlim to limit to 10 tasks at a time. The semaphore is "taken" before each task is started, and each task "releases" it when it finishes. For more about semaphores, see MSDN.

they can use simply Task.Delay(3000) but why they use await here.

Task.Delay creates a task that completes after the specified time interval and returns it. Like most Task-returning methods, Task.Delay returns immediately; it is the returned Task that has the delay. So if the code did not await it, there would be no delay.

just really do not understand after adding task to list how they can run?

In the Task-based Asynchronous Pattern, Task objects are returned "hot". This means they're already running by the time they're returned. The await Task.WhenAll at the end is waiting for them all to complete.

like image 200
Stephen Cleary Avatar answered Oct 22 '22 21:10

Stephen Cleary