Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a execution queue by using Task.ContinueWith?

I have several actions that I want to execute in the background, but they have to be executed synchronously one after the other.

I was wondering if it's a good idea to use the Task.ContinueWith method to achieve this. Do you foresee any problems with this?

My code looks something like this:

private object syncRoot =new object();
private Task latestTask;

public void EnqueueAction(System.Action action)
{
    lock (syncRoot)
    {
        if (latestTask == null)
            latestTask = Task.Factory.StartNew(action);
        else
            latestTask = latestTask.ContinueWith(tsk => action());
    }
}
like image 518
lukebuehler Avatar asked Jul 21 '11 17:07

lukebuehler


2 Answers

There is one flaw with this, which I recently discovered myself because I am also using this method of ensuring tasks execute sequentially.

In my application I had thousands of instances of these mini-queues and quickly discovered I was having memory issues. Since these queues were often idle I was holding onto the last completed task object for a long time and preventing garbage collection. Since the result object of the last completed task was often over 85,000 bytes it was allocated to Large Object Heap (which does not perform compaction during garbage collection). This resulted in fragmentation of the LOH and the process continuously growing in size.

As a hack to avoid this, you can schedule a no-op task right after the real one within your lock. For a real solution, I will need to move to a different method of controlling the scheduling.

like image 107
Bill Karn Avatar answered Nov 16 '22 07:11

Bill Karn


This should work as designed (using the fact that TPL will schedule the continuation immediately if the corresponding task already has completed).

Personally in this case I would just use a dedicated thread using a concurrent queue (ConcurrentQueue) to draw tasks from - this is more explicit but easier to parse reading the code, especially if you want to find out i.e. how many tasks are currently queued etc.

like image 32
BrokenGlass Avatar answered Nov 16 '22 09:11

BrokenGlass