Awaiting a method that is deeply nested on stack - c#

Lets say at some point at least 10 methods are available at stack as not finished. Many of these methods are dealing with actions that make impact on UI. At this point, I would like to issue a Save command. Save command can finish successfully, or can fail. Based on the result, I would like to make different actions, and only then return execution to those methods that are left on stack.
Now, if I run Save command synchronously, there is no problem. I would like to execute Save command asynchronously, return the execution to message pump (UI), while all the code (methods) on stack should wait for SaveCommand to finish.
Now, as I have understood await, there is no guarantee that a call will be made on same thread (in my case UI thread). SO, I cannot just await the first method that was called (the parent of all other methods in stack), since if a different thread gets started, it will raise a UI exception (accessing UI elements from different thread).
So, how to handle this situation? Example code:
public bool PropertyName {get; set { MethodA(); // some code after };}
public void MethodB() { MethodC(); // some code after }
public void MethodC() { MethodD(); // some code after }
public void MethodD() { MethodE(); // some code after }
// etc
void MEthodK()
{
Save();
}

If you want to (asynchronously) wait for a method, just await the Task returned from that method:
public async Task MethodCAsync() { await MethodDAsync(); // some code after }
public async Task MethodDAsync() { await MethodEAsync(); // some code after }
async Task MethodKAsync()
{
await Save();
}
This will cause a problem with your property setter, which now must be an asynchronous method:
public bool PropertyName { get; private set; }
public async Task SetPropertyNameAsync() { await MethodAAsync(); // some code after }

Unless you call ConfigureAwait(), awaiting a Task from a UI thread will always resume running your code on the UI thread.
You don't have to worry about it.

Related

Is having async producer-consumer helps to not steal a thread for duration of whole program?

The code below receives messages from tcp and passes them to the appropriate message handler. Depending on the message type, a message handler may take many minutes or several seconds to process it.
I chose the design of having a separate handler for each message type. But, now I'm thinking:
Even though I have async producer-consumer (await _messages.Reader.WaitToReadAsync()), I still have Task.Run with a loop for each message handler, meaning it will hold a whole thread from thread pool for duration of the whole program, right? So, If I have 3 message handlers, I'm holding 3 threads from thread pool, right?
Is there any benefit at all of using async producer-consumer in the way the code is currently implemented? Again, since each message handler starts Task.Run for duration of the whole program I think there is no benefit and I could use in general just a synchronous collection like BlockingCollection, right?
What is the better way to do this? Should I just have one message handler with single Task.Run that have a loop and checks for new messages and it will spawn other Task.Runs for new massage? But, I need a way to wait for the previous Task to complete and not block checking on new messages. Maybe I should have some cancelable-execution task so I could cancel the prevoius one and start a new one for same message type?
CODE
public class Distributor
{
private readonly Dictionary<string, MessageHandler> _messageHandlers;
public void StartReceive()
{
// tcpClient PSEUDO CODE
while (_tcpClient.NewMessageAvailable)
{
var data = _tcpClient.GetNewMessage();
_messageHandlers[data.MsgType].Add(data.Data);
}
}
private void RegisterMessageHandlers()
{
_messageHandlers["msgType1"] = new MyMessageHandler1(...);
_messageHandlers["msgType2"] = new MyMessageHandler2(...);
_messageHandlers["msgType3"] = new MyMessageHandler3(...);
...
}
}
public abstract class MessageHandler
{
private readonly Channel<string> _messages;
public MessageHandler()
{
_messages = Channel.CreateBounded<int>(new BoundedChannelOptions(1)
{
SingleReader = true,
SingleWriter = true,
FullMode = BoundedChannelFullMode.DropOldest,
});
}
public void Start()
{
_task = Task.Run(async () =>
{
try
{
while (await _messages.Reader.WaitToReadAsync())
{
try
{
_messages.Reader.TryRead(out var msg);
await Task.Run(async () => await HandleAsync(msg));
}
catch (Exception ex)
{
}
}
}
catch { } // OperationCanceledException
}
}
public void Add(string msg)
{
_messages.Writer.TryWrite(msg);
}
protected abstract Task HandleAsync(string msg);
}
public class MyMessageHandler1 : MessageHandler
{
protected override async Task HandleAsync(string msg)
{
// DO SOME LONG WORK
await _service1.DoWork();
}
}
public class MyMessageHandler2 : MessageHandler
{
protected override async Task HandleAsync(string msg)
{
// DO SOME WORK
await _service2.DoWork();
}
}
I still have Task.Run with a loop for each message handler, meaning it will hold a whole thread from thread pool for duration of the whole program, right? So, If I have 3 message handlers, I'm holding 3 threads from thread pool, right?
I'll answer just this question. Your assumption is wrong. You are using the Task.Run with asynchronous delegate:
_task = Task.Run(async () =>
{
while (await _messages.Reader.WaitToReadAsync())
{
//...
}
}
The _task is not running on a single thread from start to finish, unless all the awaiting inside the delegate is happening on completed awaitables, which is unlikely. Initially a ThreadPool thread is used for invoking the _messages.Reader.WaitToReadAsync method, and when the method returns that thread is released back to the ThreadPool. There is no thread involved during the await periods, and after each await a different thread might run the continuation until the next await.
Theoretically you could have thousands of tasks similar to the _task running concurrently, using only a handful of threads. The ratio tasks/threads depends on how much of the work inside the loop is synchronous, and how much is asynchronous.
To understand better the Task.Run as a mechanism, make sure to read this article by Stephen Toub: Task.Run vs Task.Factory.StartNew.

What's the right way to implement ValueTaskSource.SetCompleted

So we have this class implementing IValueTaskSource This code cannot be written as async-await because there's nothing to await on. We send a message to another running thread and get back a ValueTask that can be awaited by the caller to get the notification that the other thread has finished processing the message. However the other thread is pre-existing and already doing work. It receives the message by a completely other way; processes the message, then needs to tell the threadpool-origin thread that it finished. Thus; IValueTaskSource
There is no stock ValueTaskSource (not getting into whether or not there should be; however in this case a stock version would be of questionable utility). What we actully have looks very much like this:
class Message : IValueTaskSource {
public ValueTask Send()
{
/* how the message is sent is irrelevant */
return new ValueTask(this, 0);
}
private Action<object> continuation;
private object continuationState;
void IValueTaskSource.OnCompleted(Action<object> continuation, object state, short _, ValueTaskSourceOnCompletedFlags __)
{
lock(this) {
if (GetStatus(_) == ValueTaskSourceStatus.Pending)
{
this.continuation = continuation;
this.continuationState = state;
return;
}
continuation(continuationState); /* Suspect */
}
}
public void SetCompleted()
{
lock (this)
{
/* set state completed omitted for brevity */
continuation?.Invoke(continuationState); /* Suspect */
}
}
}
I think I'm doing this wrong. Imagine a large chain of these; it seems like it would build up too much stack. In particular, the lines marked /* Suspect */ are exactly that; and ValueTaskSourceOnCompletionFlags is unused. Although it does have the nicety in that an exception thrown by continuation always goes somewhere; assuming that's even a real issue.
Right now, the code works because there are only three of them and the continuations that use them are very much thread agnostic which thread they are on.
Based on the link to ManualResetValueTaskSource provided by Stephen Cleary and the corresponding source code I was able to produce an answer.
ManualResetValueTaskSourceCore<T> provides a complete implementation of IValueTaskSource<T> and IValueTaskSource<T>. This is currently a case of there's no void implementation so create a void implementation with a dummy type. There's some generalized debate on whether bool or object is the best dummy type but I think it doesn't really matter because member padding of T will force alignment anyway.
So the answer is to forward all the methods.
public ValueTask Send()
{
/* how the message is sent is irrelevant */
return CraeteValueTask();
}
private ManualResetValueTaskSourceCore<object> taskSource;
private ValueTask CreateValueTask() => new ValueTask(this, taskSource.Version);
public ValueTaskSourceStatus GetStatus(short version) => taskSource.GetStatus(version);
public void OnCompleted(Action<object> continuation, object state, short version, ValueTaskSourceOnCompletedFlags flags) => taskSource.OnCompleted(continuation, state, version, flags);
public void SetCompleted() => taskSource.SetResult(null);
In this case each message is in its own object so there's no pooling. Doesn't matter. Calling the existing implementation is so much easier than trying to write down the smallest correct implementation that it's still the better way.
I'm pretty sure if I were pooling value task sources the correct way would be to call Reset() inside CreateValueTask().
Here is an example using the INotifyCompletion interface to get the notification, instead of the heavier IValueTaskSource+ValueTask mechanism. The Message class is amended with just one additional instance field, an Action, and it has become awaitable by exposing a GetAwaiter method. Each Message instance is intended to be awaited only once.
public class Message : INotifyCompletion
{
private static readonly Action _completedSentinel = new(() => { });
private Action _continuation;
public Message GetAwaiter() { return this; }
public bool IsCompleted
=> ReferenceEquals(Volatile.Read(ref _continuation), _completedSentinel);
public void OnCompleted(Action continuation)
{
Action original = Interlocked.CompareExchange(ref _continuation,
continuation, null);
if (original is null) return; // Normal case
if (ReferenceEquals(original, _completedSentinel))
continuation(); // Rare case
else
throw new InvalidOperationException("Double await");
}
public void GetResult() { }
public void SetCompleted()
{
Action continuation = Interlocked.Exchange(ref _continuation,
_completedSentinel);
if (continuation is null) return;
ThreadPool.QueueUserWorkItem(state => ((Action)state).Invoke(), continuation);
}
}
Online demo.
The static _completedSentinel field is used in order to resolve a race condition that might occur, between the thread that awaits and the thread that invokes the SetCompleted method. Normally the await will happen first, but the implementation above will not break if it happens after the SetCompleted, or even if the SetCompleted is invoked between the IsCompleted/OnCompleted calls (these are called by the async/await machinery).

Is there any way to know if a method is running being awaited from within the method?

I'm a university student but, since I like programming, I try to create a library of code that's been useful to me (something like a code base).
In the process of doing this, I started designing/writing an asynchronous method that's about to be used for interlocking a variable. My goal is to produce different result when this method is being awaited (runs synchronously) and when it isn't.
An example could be the following:
private int _lock;
public async Task<bool> Lock()
{
if (method_is_not_being_awaited)
return Interlocked.Exchange(ref _lock, 1) == 0;
while (0 != Interlocked.Exchange(ref _lock, 1)) {}
return true;
}
Is there any way to achieve such result? If yes, how?
ps: I know that I could make 2 different methods bool lock() and async Task<bool> lockAsync() but, that's not what I ask for
No, it is not possible to do what you want because method must return value before any operation on result (including await) can be performed. It is not specific to async methods but rather how all code behaves in C# (and pretty much any other language).
On other hand it is pretty easy to do something that very close to what you ask - synchronously return value as soon as one tries to await the result of the method: await is essentially just call to GetAwaiter on the result and you can wire it up to alter state of your method.
Note that you can't really know what to do if method ever awaited anyway - so while you can act at moment when await is called you really can't know in advance if you should start asynchronous processing. So the best you can achieve is to do nothing in synchronous part, start asynchronous processing anyway and instantly return result when await is called (aborting/ignoring asynchronous part of the method).
Details on implementing class that can be used as result can be found in https://www.codeproject.com/Articles/5274659/How-to-Use-the-Csharp-Await-Keyword-On-Anything and https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model.
Skeleton code below shows how to implement method that does nothing unless await is called:
class MyTask
{
public MyAwaitable GetAwaiter()
{
return new MyAwaitable();
}
}
class MyAwaitable : INotifyCompletion
{
public bool IsCompleted
{
get { return true; }
}
public int GetResult()
{
return 42; // this is our "result" from method.
}
public void OnCompleted (Action continuation)
{
// just run instantly - no need to save callback as this one is
// always "completed"
continuation();
}
}
MyTask F()
{
// if your really want you can start async operation here
// and somehow wire up MyAwaitable.IsComplete to terminate/abandon
// asynchronous part.
return new MyTask();
}

How to call only few method asynchronously in C#?

I know this question has been asked for many times on stack overflow but I am looking for some suggestion on my below code. In my application there are many synchronous methods which are hard to modify. I cannot change everything to async await. But I want to run few methods asynchronously.
I have written some code for that. Also I have added the comments that will help to understand my requirement.
Here is my code:
//This class will perform some heavy operation and also going to call an API for tax configuration.
//The original class takes almost 2 sec to respond. Obviously we are refactoring it but also want this class methods to run async way
public static class TaxCalculatorHelper
{
public static Task<double> CalculateTaxAsync(double salary)
{
// I will do some heavy tax calculation here, so I want it to run asynchronously
return Task.FromResult(500.00); // currently returning temporary value
}
}
//The exisiting classes
public class Employee
{
//This method is not going to be async but What I want that Tax calculation which is heavy task that should run asynchronously
public double GetEmployeeFinalSalary(double salary)
{
var taxValue = Task.Run(async () => await TaxCalculatorHelper.CalculateTaxAsync(salary));
//I was doing this
// return taxValue.Result; // I cannot use this because it blocks the calling thread until the asynchronous operation is complete
//Is the below approach correct ?
return taxValue.GetAwaiter().GetResult();
}
}
public class SomeOtherClass
{
private readonly Employee _employee;
public SomeOtherClass()
{
_employee = new Employee();
}
//This will not be async
public void GetEmployeeCtc(double salary)
{
var finalCtc = _employee.GetEmployeeFinalSalary(salary);
}
}
Can anybody review and suggest me the best approach ?
Thank you !!
Assuming this is a UI application, then using Task.Run to push synchronous work off the UI thread is an acceptable approach. It's not a good idea in ASP.NET apps.
For your specific situation, you need to decide what to do about GetEmployeeFinalSalary.
//This method is not going to be async but What I want that Tax calculation which is heavy task that should run asynchronously
...
// return taxValue.Result; // I cannot use this because it blocks the calling thread until the asynchronous operation is complete
You need to decide whether GetEmployeeFinalSalary will be synchronous or asynchronous. If it's synchronous, then it will block the calling thread - that's what synchronous means.
I suspect that you do not want to block the calling thread (I'm assuming that's the UI thread). In that case, GetEmployeeFinalSalary must be asynchronous in order to free up the calling thread:
public async Task<double> GetEmployeeFinalSalaryAsync(double salary)
{
return await Task.Run(async () => await TaxCalculatorHelper.CalculateTaxAsync(salary));
}

Prevent Task from starting

Class TaskHolder has a property of type Task. I pass Task as a parameter into constructor and it starts immediately. Is there a way to prevent it from start?
public class Worker
{
public class TaskHolder
{
public TaskHolder(Task objective)
{
Objective = objective;
}
public Task Objective { get; set; }
}
public async Task DoSomething()
{
await Task.Delay(5000);
Debugger.Break(); // Task starts, so debugger stops here!
// Is there a way to prevent it from start?
}
[Test]
public async Task TempTest()
{
// programm starts here:
var t1 = new TaskHolder(DoSomething());
await Task.Delay(10000);
}
}
A Task represents the now-or-future result of an awaitable operation. If that task has already started, that's interesting - but it has nothing to do with the code that is receiving the task.
If you don't want to start something yet, you should probably be passing an Action. You can create a Task from an Action via Task.Run. Or you can simply invoke the action via action() or action.Invoke()`.
If what you want to run is explicitly asynchronous: you can pass Func<Task>. Again, you can start such a delegate with Task.Run if you want a Task that represents the final state. Or you can just invoke it.
(whether to Invoke() it or pass it to Task.Run() depends on whether you want it to use your thread for any of it)
Ultimately, when you called DoSomething(), you started the code running. A timer was scheduled by the Task.Delay, and then the code continued into TaskHolder.

Categories