0% found this document useful (0 votes)
147 views5 pages

C# Async Pattern

The document discusses various concepts related to concurrency and asynchrony in C#, including threading basics, tasks, asynchronous functions, cancellation tokens, progress reporting, and task combinators such as WhenAny, WhenAll, WithTimeout, and custom combinators. It provides code examples for using cancellation tokens, reporting progress, timing out tasks, handling exceptions from multiple tasks, and immediately throwing errors.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
147 views5 pages

C# Async Pattern

The document discusses various concepts related to concurrency and asynchrony in C#, including threading basics, tasks, asynchronous functions, cancellation tokens, progress reporting, and task combinators such as WhenAny, WhenAll, WithTimeout, and custom combinators. It provides code examples for using cancellation tokens, reporting progress, timing out tasks, handling exceptions from multiple tasks, and immediately throwing errors.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Chapter 14 - Concurrency and Asynchrony

Threading Basics

Tasks

Principles of Asynchrony

Asynchronous Functions in C#

Asynchronous Streams (from C# 8)

Asynchronous Patterns
Cancellation

async void Main()


{
var token = new CancellationToken();
[Link] (5000).ContinueWith (ant => [Link]()); // Tell it to cancel in two seconds.
await Foo (token);
}

// This is a simplified version of the CancellationToken type in [Link]:


class CancellationToken
{
public bool IsCancellationRequested { get; private set; }
public void Cancel() { IsCancellationRequested = true; }
public void ThrowIfCancellationRequested()
{
if (IsCancellationRequested) throw new OperationCanceledException();
}
}

async Task Foo (CancellationToken cancellationToken)


{
for (int i = 0; i < 10; i++)
{
[Link] (i);
await [Link] (1000);
[Link]();
}
}

Using the real CancellationToken

async void Main()


{
var cancelSource = new CancellationTokenSource();
[Link] (5000).ContinueWith (ant => [Link]()); // Tell it to cancel in two seconds.
await Foo ([Link]);
}

async Task Foo (CancellationToken cancellationToken)


{
for (int i = 0; i < 10; i++)
{
[Link] (i);
await [Link] (1000);
[Link]();
}
}

Using the real CancellationToken - improved version

async void Main()


{
var cancelSource = new CancellationTokenSource (5000); // This tells it to cancel in 5 seconds
await Foo ([Link]);
}

async Task Foo (CancellationToken cancellationToken)


{
for (int i = 0; i < 10; i++)
{
[Link] (i);
await [Link] (1000, cancellationToken); // Cancellation tokens propagate nicely
}
}

Progress reporting - with a delegate

async void Main()


{
Action<int> progress = i => [Link] (i + " %");
await Foo (progress);
}
Task Foo (Action<int> onProgressPercentChanged)
{
return [Link] (() =>
{
for (int i = 0; i < 1000; i++)
{
if (i % 10 == 0) onProgressPercentChanged (i / 10);
// Do something compute-bound...
}
});
}

Progress reporting - with IProgress

async void Main()


{
Action<int> progress = i => [Link] (i + " %");
await Foo (progress);
}

Task Foo (Action<int> onProgressPercentChanged)


{
return [Link] (() =>
{
for (int i = 0; i < 1000; i++)
{
if (i % 10 == 0) onProgressPercentChanged (i / 10);
// Do something compute-bound...
}
});
}

Task combinators - WhenAny

async void Main()


{
Task<int> winningTask = await [Link] (Delay1(), Delay2(), Delay3());
[Link] ("Done");
[Link] ([Link]); // 1
}

async Task<int> Delay1() { await [Link] (1000); return 1; }


async Task<int> Delay2() { await [Link] (2000); return 2; }
async Task<int> Delay3() { await [Link] (3000); return 3; }

Task combinators - WhenAny - await winning task

async void Main()


{
Task<int> winningTask = await [Link] (Delay1(), Delay2(), Delay3());
[Link] ("Done");
[Link] (await winningTask); // 1
}

async Task<int> Delay1() { await [Link] (1000); return 1; }


async Task<int> Delay2() { await [Link] (2000); return 2; }
async Task<int> Delay3() { await [Link] (3000); return 3; }

Task combinators - WhenAny - in one step

async void Main()


{
int answer = await await [Link] (Delay1(), Delay2(), Delay3());
[Link]();
}

async Task<int> Delay1() { await [Link] (1000); return 1; }


async Task<int> Delay2() { await [Link] (2000); return 2; }
async Task<int> Delay3() { await [Link] (3000); return 3; }

Task combinators - WhenAny - timeouts

async void Main()


{
Task<string> task = SomeAsyncFunc();
Task winner = await ([Link] (task, [Link](5000)));
if (winner != task) throw new TimeoutException();
string result = await task; // Unwrap result/re-throw
}

async Task<string> SomeAsyncFunc()


{
await [Link] (10000);
return "foo";
}

Task combinators - WhenAll

async void Main()


{
await [Link] (Delay1(), Delay2(), Delay3());
"Done".Dump();
}

async Task<int> Delay1() { await [Link] (1000); return 1; }


async Task<int> Delay2() { await [Link] (2000); return 2; }
async Task<int> Delay3() { await [Link] (3000); return 3; }

Task combinators - WhenAll - exceptions

async void Main()


{
Task task1 = [Link] (() => { throw null; } );
Task task2 = [Link] (() => { throw null; } );
Task all = [Link] (task1, task2);
try { await all; }
catch
{
[Link] ([Link]); // 2
}
}

Task combinators - WhenAll - return values

async void Main()


{
Task<int> task1 = [Link] (() => 1);
Task<int> task2 = [Link] (() => 2);
int[] results = await [Link] (task1, task2); // { 1, 2 }
[Link]();
}

Task combinators - WhenAll - web page downloads

async void Main()


{
int totalSize = await GetTotalSize ("[Link] [Link] [Link]
[Link]();
}

async Task<int> GetTotalSize (string[] uris)


{
IEnumerable<Task<byte[]>> downloadTasks = [Link] (uri => new WebClient().DownloadDataTaskAsync (uri));
byte[][] contents = await [Link] (downloadTasks);
return [Link] (c => [Link]);
}

Task combinators - WhenAll - web page downloads improved

async void Main()


{
int totalSize = await GetTotalSize ("[Link] [Link] [Link]
[Link]();
}

async Task<int> GetTotalSize (string[] uris)


{
IEnumerable<Task<int>> downloadTasks = [Link] (async uri =>
(await new WebClient().DownloadDataTaskAsync (uri)).Length);

int[] contentLengths = await [Link] (downloadTasks);


return [Link]();
}

Custom combinators - WithTimeout

async void Main()


{
string result = await SomeAsyncFunc().WithTimeout ([Link] (2));
[Link]();
}

async Task<string> SomeAsyncFunc()


{
await [Link] (10000);
return "foo";
}

public static class Extensions


{
public async static Task<TResult> WithTimeout<TResult> (this Task<TResult> task, TimeSpan timeout)
{
Task winner = await ([Link] (task, [Link] (timeout)));
if (winner != task) throw new TimeoutException();
return await task; // Unwrap result/re-throw
}
}

Custom combinators - WithCancellation

async void Main()


{
var cts = new CancellationTokenSource (3000); // Cancel after 3 seconds
string result = await SomeAsyncFunc().WithCancellation ([Link]);
[Link]();
}

async Task<string> SomeAsyncFunc()


{
await [Link] (10000);
return "foo";
}

public static class Extensions


{
public static Task<TResult> WithCancellation<TResult> (this Task<TResult> task, CancellationToken cancelToken)
{
var tcs = new TaskCompletionSource<TResult>();
var reg = [Link] (() => [Link] ());
[Link] (ant =>
{
[Link]();
if ([Link])
[Link]();
else if ([Link])
[Link] ([Link]);
else
[Link] ([Link]);
});
return [Link];
}
}

Custom combinators - WhenAllOrError

// This will throw an exception immediately.

async void Main()


{
Task<int> task1 = [Link] (() => { throw null; return 42; } );
Task<int> task2 = [Link] (5000).ContinueWith (ant => 53);

int[] results = await WhenAllOrError (task1, task2);


}

async Task<TResult[]> WhenAllOrError<TResult> (params Task<TResult>[] tasks)


{
var killJoy = new TaskCompletionSource<TResult[]>();

foreach (var task in tasks)


[Link] (ant =>
{
if ([Link])
[Link]();
else if ([Link])
[Link] ([Link]);
});

return await await [Link] ([Link], [Link] (tasks));


}

C# 12
in a Nutshell
About the Book

Code Listings
C# 12 in a Nutshell
C# 10 in a Nutshell
C# 9.0 in a Nutshell
C# 8.0 in a Nutshell
C# 7.0 in a Nutshell

Extras
Contact

Buy print or Kindle edition

Buy PDF edition

Read via O'Reilly subscription

You might also like