Asynchronous Support

All distributed methods on all Ignite.NET APIs can be executed either synchronously or asynchronously. These methods are presented as DoSomething/DoSomethingAsync pairs. Async methods follow Task-based Asynchronous Pattern: they return System.Threading.Task and can be awaited using C# 5 "await" keyword.

Async methods that support cancellation have overloads with CancellationToken parameter.

Compute Grid Example

The example below illustrates the difference between synchronous and asynchronous computations.

ICompute compute = ignite.GetCompute();

// Execute a job and wait for the result.
string res = compute.Call(new ComputeFunc());

Console.WriteLine(res);

Here is how you would make the above invocation asynchronous:

// Start asynchronous operation and obtain a Task that represents it
Task<string> asyncRes = compute.CallAsync(new ComputeFunc());

// Synchronously wait for the task to complete and obtain result
Console.WriteLine(asyncRes.Result);

// OR use C# 5 await keyword
Console.WriteLine(await asyncRes);

// OR use continuation
asyncRes.ContinueWith(task => Console.WriteLine(task.Result));

Data Grid Example

Here is the data grid example for synchronous and asynchronous invocations.

ICache<int, string> cache = ignite.GetCache<int, string>("myCache");

CacheResult<string> val = cache.GetAndPut(1, "1");

Here is how you would make the above invocation asynchronous.

// Start asynchronous operation and obtain a Task that represents it
Task<CacheResult<string>> asyncVal = cache.GetAndPutAsync(1, "1");

// Synchronously wait for the task to complete and obtain result
Console.WriteLine(asyncVal.Result.Success);

// Use C# 5 await keyword
Console.WriteLine((await asyncVal).Success);

// Use continuation
asyncVal.ContinueWith(task => Console.WriteLine(task.Result.Success));

Async Continuations

Async operations in Ignite are completed from special system threads. These threads have the following limitations:

  • Ignite APIs should not be used
  • Heavy operations should not be performed

Your code can end up in Ignite system thread when you use ConfigureAwait(false) with async keyword:

var cache = ignite.GetCache<int, int>("ints");

await cache.PutAsync(1, 1).ConfigureAwait(false);
// All the code below executes in Ignite system thread.
// Do not access Ignite APIs from here.

If you need to perform multiple awaited operations, do not use ConfigureAwait(false).

For Console, ASP.NET Core, and some other types of applications the default System.Threading.SynchronizationContext is not set, so a custom SynchronizationContext is required to avoid running continuations on Ignite system threads. The simplest way is to derive from SynchronizationContext class like this:

class Program
{
    public static async Task<int> Main()
    {
        // Run async continuations on .NET Thread Pool threads.
        SynchronizationContext.SetSynchronizationContext(
             new ThreadPoolSynchronizationContext());
      
        using (var ignite = Ignition.Start())
        {
            var cache = ignite.GetOrCreateCache<int, string>("my-cache");
            await cache.PutAsync(1, "Test1");
            await cache.PutAsync(2, "Test2");
            await cache.PutAsync(3, "Test3");
        }

        return 0;
    }
}

class ThreadPoolSynchronizationContext : SynchronizationContext
{
    // No-op.
    // Don't use SynchronizationContext class directly because optimization 
    // in the Task class treats that the same way as null context.
}