0% found this document useful (0 votes)
7 views31 pages

Asynchronous Programming Advanced Topics Slides

The document discusses advanced topics in asynchronous programming, focusing on task progress reporting and the use of IProgress<T> for managing progress updates. It explains the implementation of TaskCompletionSource for creating awaitable tasks from legacy code, and the various overloads of Task.Factory.StartNew for task creation. Additionally, it highlights the importance of task hierarchy and synchronization between parent and child tasks in asynchronous operations.
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)
7 views31 pages

Asynchronous Programming Advanced Topics Slides

The document discusses advanced topics in asynchronous programming, focusing on task progress reporting and the use of IProgress<T> for managing progress updates. It explains the implementation of TaskCompletionSource for creating awaitable tasks from legacy code, and the various overloads of Task.Factory.StartNew for task creation. Additionally, it highlights the importance of task hierarchy and synchronization between parent and child tasks in asynchronous operations.
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
You are on page 1/ 31

Asynchronous Programming

Advanced Topics

Filip Ekberg
Principal Consultant & CEO

@fekberg fekberg.com
Report on the Progress of a Task
Out of the box the Task
does not automatically report
the progress
What Determines the Progress?

Is it how much of the data that Is it how much of the data that
has been loaded? is completely processed?
Progress<T>
“Provides an IProgress<T> that invokes callbacks for each reported progress
value.”

learn.microsoft.com/en-us/dotnet/api/system.progress-1?view=net-6.0
Progress<T>

var progress = new Progress<string>();

progress.ProgressChanged = (_, string progressValue) => {

// Use the “progressValue” here!

};
Progress reporting can be
complex and diffucult but it’s
made easier with
IProgress<T>
There is no way for a task to
automatically figure out its
own progress

We have to introduce
something like Progress<T>
Using Task Completion Source
How Would You Use This with Async & Await?

Event-based asynchronous Manually queue work on the


pattern thread pool
Event-based Asynchronous Pattern

var worker = new BackgroundWorker();

worker.DoWork += (sender, e) => {


// Runs work on a different thread
};

worker.RunWorkerCompleted += (sender, e) => {


// Event triggered when work is done
};
Manually Queue Work on the Thread Pool

ThreadPool.QueueUserWorkItem(_ => {

// Run work on a different thread

});
TaskCompletionSource<T>
“Represents the producer side of a Task<T> unbound to a delegate,
providing access to the consumer side through the Task property.”

learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1?view=net-6.0
Task Completion Source

var tcs = new TaskCompletionSource<string>();

Task<string> task = tcs.Task;


Use TaskCompletionSource to
create awaitables out of legacy
code that don’t use the TPL
Working with Attached and Detached Tasks
Nested / Child Tasks

Task.Run(() => {

Task.Run(() => {});


These are child tasks
Task.Run(() => {});

});
Task.Factory.StartNew Overloads
StartNew(Action)
StartNew(Action, CancellationToken)
StartNew(Action, TaskCreationOptions)
StartNew(Action, CancellationToken, TaskCreationOptions, TaskScheduler)

StartNew(Action<Object>, Object)
StartNew(Action<Object>, Object, CancellationToken)
StartNew(Action<Object>, Object, TaskCreationOptions)
StartNew(Action<Object>, Object, CancellationToken,
TaskCreationOptions, TaskScheduler)

+ 8 more
Task.Factory.StartNew Overloads
StartNew(Action)
StartNew(Action, CancellationToken)
StartNew(Action, TaskCreationOptions)
StartNew(Action, CancellationToken, TaskCreationOptions, TaskScheduler)

StartNew(Action<Object>, Object)
StartNew(Action<Object>, Object, CancellationToken)
StartNew(Action<Object>, Object, TaskCreationOptions)
StartNew(Action<Object>, Object, CancellationToken,
TaskCreationOptions, TaskScheduler)

+ 8 more
Task.Factory.StartNew Overloads
StartNew(Action)
StartNew(Action, CancellationToken)
StartNew(Action, TaskCreationOptions)
StartNew(Action, CancellationToken, TaskCreationOptions, TaskScheduler)

StartNew(Action<Object>, Object)
StartNew(Action<Object>, Object, CancellationToken)
StartNew(Action<Object>, Object, TaskCreationOptions)
StartNew(Action<Object>, Object, CancellationToken,
TaskCreationOptions, TaskScheduler)

+ 8 more
Task.Factory.StartNew Overloads
StartNew(Action)
StartNew(Action, CancellationToken)
StartNew(Action, TaskCreationOptions)
StartNew(Action, CancellationToken, TaskCreationOptions, TaskScheduler)

StartNew(Action<Object>, Object)
StartNew(Action<Object>, Object, CancellationToken)
StartNew(Action<Object>, Object, TaskCreationOptions)
StartNew(Action<Object>, Object, CancellationToken,
TaskCreationOptions, TaskScheduler)

+ 8 more
Task.Factory.StartNew Overloads
StartNew(Action)
StartNew(Action, CancellationToken)
StartNew(Action, TaskCreationOptions)
StartNew(Action, CancellationToken, TaskCreationOptions, TaskScheduler)

StartNew(Action<Object>, Object)
StartNew(Action<Object>, Object, CancellationToken)
StartNew(Action<Object>, Object, TaskCreationOptions)
StartNew(Action<Object>, Object, CancellationToken,
TaskCreationOptions, TaskScheduler)

+ 8 more
Using Task.Run is in most situations
the best option
AttachedToParent
“Specifies that a task is attached to a parent in the task hierarchy. By default, a child
task (that is, an inner task created by an outer task) executes independently of its
parent.
You can use the AttachedToParent option so that the parent and child tasks are
synchronized.
Note that if a parent task is configured with the DenyChildAttach option, the
AttachedToParent option in the child task has no effect, and the child task will
execute as a detached child task.”

learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-6.0
If a parent task is configured with
the DenyChildAttach option

AttachedToParent option in the


child task has no effect
Task.Run Automatically Unwraps!
Task<string> task = Task.Run(async () => {
await Task.Delay(1000);

return ”Pluralsight”;
});

Task<Task<string>> taskFromFactory = Task.Factory.StartNew(async () => {


await Task.Delay(1000);

return ”Pluralsight”;
});

Task<string> unwrappedTask = taskFromFactory.Unwrap();


Passing a Value to Task.Factory.StartNew

IEnumerable<StockPrice> stocks = ...


Task.Factory.StartNew((state) => {

// Cast the state to the correct type


var items = state as IEnumerable<StockPrice>

}, stocks);
Passing a Value to Task.Factory.StartNew

IEnumerable<StockPrice> stocks = ...


Task.Factory.StartNew((state) => {

// Cast the state to the correct type


var items = state as IEnumerable<StockPrice>

}, stocks); Using “stocks” directly in the anonymous


method would introduce a clojure
Passing a Value to Task.Factory.StartNew

IEnumerable<StockPrice> stocks = ...


Task.Factory.StartNew((state) => {

// Cast the state to the correct type


var items = state as IEnumerable<StockPrice>

}, stocks);

You can pass a reference to the object


which will be used by the asynchronous
operation
Passing a Value to Task.Factory.StartNew

IEnumerable<StockPrice> stocks = ...


Task.Factory.StartNew((state) => {

// Cast the state to the correct type


var items = state as IEnumerable<StockPrice>

}, stocks);
Task.Run
Task.Run(() => {});

Internally uses the factory with these


default values

Task.Factory.StartNew(
() => {},
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default
);

You might also like