I have a class that handles some hardware. I want this class to check some state of the hardware every N milleseconds, and fire an event if a certain case is true.
I would like the interface on the outside to be such:
var rack = new Rack();
rack.ButtonPushed += OnButtonPushed;
rack.Initialise();
I want to avoid using "real" threads, but I don't seem to get the Task correctly (for testing, I just fire the event every second):
class Rack {
public event EventHandler ButtonPushed;
public void Initialise()
{
Task.Run(() =>
{
while (true)
{
Task.Delay(1000);
ButtonPushed?.Invoke(this, null);
}
});
}
}
But this doesn't work, the events get fired all at the same time.
Is Task the right thing to use here, or should I work with a Timer, or a thread?
Task delay returns a task that finishes execution after given time and needs to be awaited. In order to await it we'd need to mark the delegate as async and add await before the call:
class Rack {
public event EventHandler ButtonPushed;
public void Initialise()
{
Task.Run(async () =>
{
while (true)
{
await Task.Delay(1000);
ButtonPushed?.Invoke(this, null);
}
});
}
}
Is Task the right thing to use here, or should I work with a Timer, or
a thread?
Well, your approach is just as good as using Timer. Thread could be used as well but it's a bit too low-level approach.
As others mentioned it would be better with CancellationToken, this allows us to cancel the task later so it finishes execution:
while (!cancellationToken.IsCancellationRequested)
{
...
}
Related
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.
For asynchronous delegates in the code, I do the following everywhere:
public class SomeCaller
{
public event Action SomeChanged;
public event Func<Task> SomeChangedAsync;
//If in Caller async method
public async Task SomeMethodAsync()
{
SomeChanged?.Invoke();
if (SomeChangedAsync != null)
await SomeChangedAsync();
}
//if in Caller synchronous method
public void SomeMethod()
{
SomeChanged?.Invoke();
if (SomeChangedAsync != null)
Task.Run(async () => await SomeChangedAsync());
}
}
Is there any point in such a solution (to separate the event for async) or is this an example of poor design?
If this is bad, then I would like to understand why and how best to call async delegates?
The invocation of the SomeChangedAsync event is not implemented correctly. In case of multiple event handlers, only the last handler attached will be awaited. To await all the handlers you must get them with the method GetInvocationList, and then decide how you want to invoke and await them. Here is a sequential approach:
public async Task SomeMethodAsync()
{
SomeChanged?.Invoke();
Delegate[] delegates = SomeChangedAsync?.GetInvocationList();
if (delegates != null)
{
var taskFactories = delegates.Cast<Func<Task>>().ToArray();
foreach (var taskFactory in taskFactories)
{
var task = taskFactory();
await task;
}
}
}
You can also invoke and await them all at once (using Task.WhenAll), as it's suggested here.
is this an example of poor design?
This is probably a poor design. The synchronous version raises the delegates on a thread pool thread (instead of whatever thread caused the event), and it raises them as fire-and-forget, which means any exceptions will be silently swallowed and ignored. That's usually bad.
If this is bad, then I would like to understand why and how best to call async delegates?
You need to call asynchronous delegates asynchronously - from an asynchronous method. It's not always possible to safely call an asynchronous method (or delegate) synchronously, though there are some hacks that work in most situations.
I have a class with properties that are bound to my view. To keep my view up-to-date, I implement INotifyPropertyChanged and raise the event everytime some property changes.
Now I got some heavy functions that freeze my application. I want to put them into a background task.
First: here my current approach
(e.g. on button click)
private async void HeavyFunc()
{
foreach (var stuff)
{
count += await Task.Run(() => stuff.Fetch());
}
if (count == 0)
//...
}
stuff class
public async Task<int> Fetch()
{
//network stuff
RaisePropertyChanged("MyProperty");
}
public async void RaisePropertyChanged(string pChangedProperty)
{
await Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new ThreadStart(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty);
}
);
}
The code above gives an exception ("DependencySource" must be created in the same thread like "DependencyObject").
AFAIK, you generally need to create a new thread and run it (while awaiting it). ´await Task.Run(...);´ should do this job.
Since the PropertyChanged event directly influences the UI, calling it in the UI thread seems to be a good decision. This is why I call Dispatcher.BeginInvoke.
What I don't understand: the exception above is caused when different threads are responsible for the data. But I explicitely calling the event on my UI-thread and the object should be created by the UI-thread too. So why do I get an exception?
My main question is: How do I implement the events for the INotifyPropertyChanged interface generally to avoid or handle most of the async programming problems like above? What should be considered while constructing the functions?
Now I got some heavy functions that freeze my application.
If you're really doing asynchronous "network stuff", then it shouldn't be freezing the app.
My main question is: How do I implement the events for the INotifyPropertyChanged interface generally to avoid or handle most of the async programming problems like above?
The approach that I prefer is to not handle this in the event raising code. Instead, structure the rest of your code so that it respects the UI layer.
In other words, divide your "service" (or "business logic") code from your "UI" code so that it works like this:
// In StuffService class:
public async Task<Result> FetchAsync()
{
//network stuff
return result;
}
// In StuffViewModel class:
public async void ButtonClicked()
{
foreach (var stuff)
{
var result = await Task.Run(() => _stuffService.FetchAsync());
MyProperty = result.MyProperty;
count += result.Count;
}
if (count == 0)
//...
}
public Property MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty));
}
This way, there's no manual thread jumping, all properties have the standard ViewModel implementation, the code is simpler and more maintainable, etc.
I did leave in the call to Task.Run, although this should be superfluous if your network calls are truly asynchronous.
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.
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.