Calling void async equals Task.Run? [duplicate] - c#

This question already has answers here:
Do you have to put Task.Run in a method to make it async?
(3 answers)
Closed 1 year ago.
When I call an async method which returns void, is it the same as when I invoke it with the Task.Run method? I ask because in the doc of the FileSystemWatcher they mention the following.
Keep your event handling code as short as possible.
https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?view=net-5.0#events-and-buffer-sizes
So I want to leave the scope of the event method very fast. Or do they mean something different?
Snippet of my code for better understanding.
private void OnCreated(object sender, FileSystemEventArgs e)
{
RunSaveWithLogger(AddLocation, e.FullPath);
}
private async void RunSaveWithLogger(Func<string, Task> func, string fullPath)
{
Edit:
After reading your answers and comments, I changed my code to this.
private void OnCreated(object sender, FileSystemEventArgs e)
{
Task.Run(() =>
{
RunSaveWithLogger(AddLocation, e.FullPath);
});
}
private async void RunSaveWithLogger(Func<string, Task> func, string fullPath)
{
try
{
await func.Invoke(fullPath);
}
catch (Exception exception)
{
_logger.LogError(exception, "");
}
}
Thanks for your time and help, I really appreciate that.

simple answer No! they are not the same. for instance, in the example below, "Task.Run" creates a new thread and so, runs every code within it in a new thread, while "async void" doesn't. (I doubt if this is the answer you are looking for though).
using System;
using System.Threading.Tasks;
class Solution
{
static void Main(string[] args)
{
async void Method1()
{
while (true)
{
}
}
Task.Run(() => {
while (true)
{
}
});
Console.WriteLine("This will print");
Method1();
Console.WriteLine("This won't");
}
}

Related

C# Async recursive function not working properly? [duplicate]

This question already has answers here:
async/await - when to return a Task vs void?
(6 answers)
Closed 2 years ago.
This is my code :
class Program
{
static void Main(string[] args)
{
update();
}
static async void update()
{
await Task.Delay(100);
Console.WriteLine("X");
update();
}
}
Console never outputs any text at all, and I have no clue why. What am I doing wrong?
Your Main method is not async, so it doesn't wait for your update method. Also, your update method should return a Task so your Main method can await it.
static async Task Main(string[] args)
{
await update();
}
static async Task update()
{
await Task.Delay(100);
Console.WriteLine("X");
await update();
}

To get Result from Task.Run without await

I have a snippet that looks like this,
private void btn_Click(object sender, EventArgs e)
{
try
{
var res = Task.Run(() => DoTask(param1, param2));
if(res.IsCompleted)
{
MessageBox.Show("Done");
}
MessageBox.Show("DoTask isn't called yet.");
}
catch
{
MessageBox.Show("Something wrong");
}
}
The DoTask method looks like this
private async Task<bool> DoTask(int p1, int p2)
{
// run long tasks
}
I'd want to show Done message after the task is done. But this never works. Instead the message DoTask isn't called yet. is always called before DoTask does tasks.
Panagiotis' answer is the way to go. Should you have the same situation in a method that is not an event handler and you can't use async for some reason, here's the next best option:
Task<bool> task = Task.Run(() => DoTask(param1, param2));
bool res = task.GetAwaiter().GetResult();
To get Result from Task.Run without await
The proper way to get a result from an asynchronous task is to use await:
private async void btn_Click(object sender, EventArgs e)
{
try
{
var res = await Task.Run(() => DoTask(param1, param2));
if(res)
{
MessageBox.Show("Done");
}
MessageBox.Show("DoTask isn't called yet.");
}
catch
{
MessageBox.Show("Something wrong");
}
}
Note that you should usually avoid async void, but since this code is an event handler, the async void is OK.
Simple Way:
bool result = DoTask(paran1, param2).Result;
No need to use Task.Run(). But you can use it in the following way (BAD WAY):
bool result = Task.Run(() => DoTask(paran1, param2).Result).Result;

Why is `async void` a necessary part of the C# language?

The common description of why async void is part of C# is for event handlers. For example:
private async void button_Click(object sender, RoutedEventArgs e)
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("http://example.com");
var content = await response.Content.ReadAsStringAsync();
this.textBox.Text = content;
}
}
I find this reason unsatisfying, as this kind of event handler can be written without async void like this:
private void button_Click(object sender, RoutedEventArgs e)
{
button_ClickAsync().ForgetTask();
}
private async Task button_ClickAsync()
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("http://example.com");
var content = await response.Content.ReadAsStringAsync();
this.textBox.Text = content;
}
}
static class TaskExtensions { public static void ForgetTask(this Task task) { } }
Why isn't the latter good enough? Why is async void a necessary part of C#? What problem can't be solved without async void?
As you showed yourself, it's not necessary. You can write a functionally identical program to one that uses it without using it. It's useful insofar as there simply are times where you really do want to create an async method that doesn't expose any way of observing the result, such as in the situation you mentioned. Could they have designed the feature in such a way that users could accomplish that another way, yes, you showed one possible way, the C# language designers choose another.
Exceptions from an unawaited async Task method will be unobserved, firing the TaskScheduler.UnobservedTaskException event. For example:
static void Main()
{
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs args) => { Console.WriteLine(args.Exception.InnerException.Message + " unobserved"); };
try
{
ThrowExceptionInAsyncTask();
Console.WriteLine("ThrowExceptionInAsyncTask not caught");
}
catch (Exception)
{
Console.WriteLine("ThrowExceptionInAsyncTask caught");
}
GC.Collect();
try
{
ThrowExceptionInAsyncVoid();
Console.WriteLine("ThrowExceptionInAsyncVoid not caught");
}
catch (Exception)
{
Console.WriteLine("ThrowExceptionInAsyncVoid caught");
}
GC.Collect();
}
static async Task ThrowExceptionInAsyncTask()
{
throw new InvalidOperationException("ThrowExceptionInAsyncTask");
}
static async void ThrowExceptionInAsyncVoid()
{
throw new InvalidOperationException("ThrowExceptionInAsyncVoid");
}
Produces:
ThrowExceptionInAsyncTask not caught
ThrowExceptionInAsyncVoid not caught
ThrowExceptionInAsyncTask unobserved
It is used in two cases as in my own knowledge:
In event handlers. Because event handlers cannot have a return type.
In a method intended to have no return type, and not awaited.
What you did here is a good workaround, but think of it as flexibility in language to make life easier for developers and simplify language syntax. Same example like yours is: Why System.Linq exists in C#?! Why we can use syntax like myIntArray.Max() while we can iterate through the array and find the maximum value!
That doesn't mean there is no other reason, but I'm sharing my thoughts and I hope that helps.

how to notify method that something is done

My constructor besides other things call another method DoWork
public MyTask(TaskAction action)
{
DoWork(action);
}
DoWork method goes to another method Calc(2)
private void Calc (int 2){
... calc and save result into file
}
How can I alert MyTask that Calc is done and let MyTask to continue further.
P.S. I could read hdd every few secs in order to see whether file with result is save and based on that continue further, but I assume that there is better way.
BackgroundWorker class allows you to easily manage your async work.
BackgroundWorker _worker = new BackgroundWorker();
public Cnt()
{
InitializeComponent();
_worker.DoWork += WorkerOnDoWork;
_worker.RunWorkerCompleted += WorkerOnRunWorkerCompleted;
//start your work
_worker.RunWorkerAsync();
}
private void WorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Worker completed event
}
private void WorkerOnDoWork(object sender, DoWorkEventArgs e)
{
//Do
}
There are many ways to do this.The latest recommended is using tasks
Task taskA = new Task(() => { Console.WriteLine("Task A started"); });
taskA.ContinueWith((ss) => { Console.WriteLine("Task A finished"); });
taskA.Start();
http://msdn.microsoft.com/en-us/library/ee372288(v=vs.110).aspx
This way you can block the current thread if you want.
Another way is the BackGroundWorker Class
Also, you can use a custom callback like this
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DoWorkA(DoWorkFinished);
Console.Read();
}
private static void DoWorkA(Action whatToDoWhenFinished)
{
Console.WriteLine("Doing something");
whatToDoWhenFinished();
}
private static void DoWorkFinished()
{
Console.WriteLine("Doing something Else");
}
}
}

Is it possible to have async methods as callbacks to eventhandlers in c#?

My design is illustrated by below example. Having a while true loop doing something and notifying by an event that it has done something to all subscribers. My application should not continue its execution before its done notifying all subscribers, where this works as long as someone do not put a async void on the callback.
If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.
Its 3th party plugins that register themeself and subscribe to the event, so I have no control over if they put a async void. Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Test
{
public event EventHandler Event;
public void DoneSomething()
{
if (Event != null)
Event(this,EventArgs.Empty);
}
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
test.Event += test_Event;
test.Event +=test_Event2;
while(true)
{
test.DoneSomething();
Thread.Sleep(1000);
}
}
private static void test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
}
static async void test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}
}
}
If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.
There is really no way to avoid this. Even if you were to somehow "know" that the subscriber wasn't implemented via async/await, you still couldn't guarantee that the caller didn't build some form of asynchronous "operation" in place.
For example, a completely normal void method could put all of its work into a Task.Run call.
My application should not continue its execution before its done notifying all subscribers
Your current version does follow this contract. You're notifying the subscribers synchronously - if a subscriber does something asynchronously in response to that notification, that is something outside of your control.
Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.
Note that this is actually possible. For example, you can rewrite your above as:
public class Program
{
public static void Main()
{
var test = new Test();
test.Event += test_Event;
test.Event +=test_Event2;
test.DoneSomethingAsync().Wait();
}
}
public delegate Task CustomEvent(object sender, EventArgs e);
private static Task test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
return Task.FromResult(false);
}
static async Task test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}
public class Test
{
public event CustomEvent Event;
public async Task DoneSomethingAsync()
{
var handler = this.Event;
if (handler != null)
{
var tasks = handler.GetInvocationList().Cast<CustomEvent>().Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
}
You can also rewrite this using event add/remove, as suggested by svick:
public class Test
{
private List<CustomEvent> events = new List<CustomEvent>();
public event CustomEvent Event
{
add { lock(events) events.Add(value); }
remove { lock(events) events.Remove(value); }
}
public async Task DoneSomething()
{
List<CustomEvent> handlers;
lock(events)
handlers = this.events.ToList(); // Cache this
var tasks = handlers.Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
My application should not continue its execution before its done notifying all subscribers, where this works as long as someone do not put a async void on the callback.
I have a blog entry on designing for async event handlers. It is possible to use Task-returning delegates or to wrap an existing SynchronizationContext within your own (which would allow you to detect and wait for async void handlers).
However, I recommend you use "deferrals", which are objects designed specifically to solve this problem for Windows Store applications. A simple DeferralManager is available in my AsyncEx library.
Your event args can define a GetDeferral method as such:
public class MyEventArgs : EventArgs
{
private readonly DeferralManager deferrals = new DeferralManager();
... // Your own constructors and properties.
public IDisposable GetDeferral()
{
return deferrals.GetDeferral();
}
internal Task WaitForDeferralsAsync()
{
return deferrals.SignalAndWaitAsync();
}
}
And you can raise an event and (asynchronously) wait for all asynchronous handlers to complete like this:
private Task RaiseMyEventAsync()
{
var handler = MyEvent;
if (handler == null)
return Task.FromResult<object>(null); // or TaskConstants.Completed
var args = new MyEventArgs(...);
handler(args);
return args.WaitForDeferralsAsync();
}
The benefit of the "deferral" pattern is that it is well-established in the Windows Store APIs, so it's likely to be recognized by end users.

Categories