Getting Started
To use this library, simply include Icicle.dll
in your project or
grab
it from NuGet, and add
this to the top of each .cs
file that needs it:
using Icicle;
Now a TaskScope can be created.
A fully parallel
scope looks like this,
// within a using block, create a scope and configure it
using TaskScope scope = new TaskScope.WhenAll(); // run all tasks at the same time
// now add tasks to the scope to run
ResultHandle t1 = scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct));
ResultHandle t2 = scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct));
ResultHandle t3 = scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct));
// now run them all; should run for around a second
RunToken token = await scope.Run();
Values can also be returned from the added tasks,
using TaskScope scope = new TaskScope.WhenAll();
// added tasks
ResultHandle<string> t1 = scope.Add(async ct =>
{
await Task.Delay(TimeSpan.FromSeconds(1), ct);
return "Hello";
});
ResultHandle<string> t2 = scope.Add(async ct =>
{
await Task.Delay(TimeSpan.FromSeconds(1), ct);
return "World";
});
// now run them all; should run for around a second
var token = await scope.Run();
// set the value to "Hello World"
Assert.Equal("Hello World", $"{t1.Value(token)} {t2.Value(token)}");
The usage rules for TaskScope are as follows,
Add can be called as many times as required up until Run has completed (nested calls to Add are supported)
using TaskScope scope = new TaskScope.WhenAll(); // keep adding ResultHandle t1 = scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct)); ResultHandle t2 = scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct)); ResultHandle t3 = scope.Add(async ct => { await Task.Delay(TimeSpan.FromSeconds(1), ct); // and nest as well _ = scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct)); }); // run them RunToken token = await scope.Run(); // cannot call Add or Run from this point on Assert.Throws<TaskScopeCompletedException>( () => scope.Add(async ct => await Task.Delay(TimeSpan.FromSeconds(1), ct)) );
Run can only be called once, and must be called
This enforces the following semantics,
All suspended tasks are only started on Run and conform to the particular execution semantics of the TaskScope instance and its configuration. For example, a
windowSize
if provided to TaskScope.WhenAll will run at mostwindowSize
tasks at a timeAny Fault will trigger cancellation
Cancellation applies to tasks that are started, all other tasks that have not started never start
Values can be accessed from ResultHandle<T> and ResultHandle after Run
using TaskScope scope = new TaskScope.WhenAll(); ResultHandle<string> t1 = scope.Add(async ct => { await Task.Delay(TimeSpan.FromSeconds(1), ct); return "Hello"; }); RunToken token = await scope.Run(); // get token here string result = t1.Value( // pass it here token ); Assert.Equal("Hello", result);