12

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

CarenRose
  • 1,266
  • 1
  • 12
  • 24
Thomas
  • 33,544
  • 126
  • 357
  • 626
  • "here task & ss.release is added to list" -> "trackedTasks.Add(Task.Run(" has 2 pieces. 1 = "Add something to the list" => trackedTasks.Add( , 2 = "Start a new task" ->Task.Run. – Marvin Smit Nov 15 '13 at 10:38

1 Answers1

18

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.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • why Task.Delay return immediately rather as name implies delay() then it should make some delay()...isn't ? – Thomas Nov 15 '13 at 14:35
  • what is the difference between Semaphore & SemaphoreSlim classes? can u plzz redirect me to a best url from where i can read & see the code about various usage of TPL library. thanks – Thomas Nov 15 '13 at 14:37
  • 1
    please see my first set of code. there u see DoPollingThenWorkAsync() function is getting call from WorkerMainAsync() function but no SemaphoreSlim instance is getting pass to DoPollingThenWorkAsync(). is it a mistake or typo ? – Thomas Nov 15 '13 at 14:39
  • 3
    As the name implies, `Task.Delay` returns a task representing a delay. The difference between `Semaphore` and `SemaphoreSlim` is covered in the [same MSDN link](http://msdn.microsoft.com/en-us/library/z6zx288a%28v=vs.110%29.aspx). The first code sample has a typo; it should be passing the `SemaphoreSlim` instance to the worker method. – Stephen Cleary Nov 15 '13 at 15:46
  • @StephenCleary: Could you please include your comment above in your answer. (I tried an edit but it has been declined.) – participant Oct 07 '14 at 07:56
  • 3
    @participant: I think it is good as-is. The answer answers the question, and the comments answer the additional questions asked in the comments. – Stephen Cleary Oct 07 '14 at 11:54