Problem

You want to dynamically change the consumed resources of the task.

Solution

Use the IJobSchedulerContext interface and call YieldResource to decrease the resources consumed by the task and ReserveResource to increase the resources consumed by the task.

C#  Copy imageCopy
using System;
using AGI.Parallel.Client;
using AGI.Parallel.Infrastructure;

namespace CodeSamples
{
    class Program
    {
        static void Main(string[] args)
        {
            using (IJobScheduler scheduler = new ClusterJobScheduler("localhost"))
            {
                scheduler.Connect();
                Task task = new YieldResourceDemo();
                Job job = scheduler.CreateJob();
                job.AddTask(task);
                job.Submit();
                job.WaitUntilDone();

                Console.WriteLine(task.StandardOutput);
            }

            /*
             * The output of the application should resemble:
             * Initial: Consuming 1 Cores
             * After YieldResource: Consuming 0 Cores
             * After ReserveResource: Consuming 1 Cores
             */
        }

        [Serializable]
        public class YieldResourceDemo : Task
        {
            public override void Execute()
            {
                IJobSchedulerContext jobSchedulerContext = this.GetProperty<IJobSchedulerContext>(TaskProperties.JobSchedulerContext);

                // You can pass 0 to query that amount the task is currently consuming.
                long currentConsumption = jobSchedulerContext.YieldResource(ConsumableResources.Cores, 0);
                Console.WriteLine("Initial: Consuming {0} Cores", currentConsumption);

                // Let's yield the resource to the global resource poll
                currentConsumption = jobSchedulerContext.YieldResource(ConsumableResources.Cores, 1);
                Console.WriteLine("After YieldResource: Consuming {0} Cores", currentConsumption);

                // We can also dynmically increase our resource consumption.
                currentConsumption = jobSchedulerContext.ReserveResource(ConsumableResources.Cores, 1);
                Console.WriteLine("After ReserveResource: Consuming {0} Cores", currentConsumption);
            }
        }
    }
}

Discussion

Accurate resource tracking is important for efficiently using all available resources. A high degree of flexibility is allowed for more advanced cases where more control is needed for specifying which task is consuming which resource. Resource yielding comes in handy when a known task is not doing any real work and the system should consider its resources available to the system. The most common use case for this is when the task is waiting for work to be done. Resource reserving is much less common. Reserve a resource when more work is about to be done and the system should be notified.

Resources also have a concept of private and global availability. A global resource is the most common and the default. Global resources are available to all tasks--there are no restrictions. A private resource is a special kind of resource that restricts who can consume it, most commonly children of the task. Make a resource private by specifying true to the restrictToChildren parameter of YieldResource. Resources from private resources are consumed first before consuming global resources. The most common reason for using private resources over global resources is to ensure child tasks will have a pool of resources available only to them. That is, using private resources can guarantee that a child task will not have to wait in the queue because it does not have the necessary resources.

Important

When a task submits a child job all of its resources are yielded by default. You will only have to yield resources if you choose to manually do so.

See Also