1

Trying to achieve Fire and Forget:

class Program
{
    static void Main(string[] args)
    {
       var my = new MyClass();

       my.OrderForm_Load();
       Console.ReadLine();
    }

}

internal class MyClass
{
    //Blocking
    public void OrderForm_Load()
    {
        var t1 = new ServiceTask();

        Task.Run(() => t1.PersistTask()); //Approach 1:
        //[OR]            
        t1.PersistTask(); //Approach 2: Has compiler errors CS4014
        Console.WriteLine("Second");
    }
}

internal class ServiceTask
{
    //Non-Blocking
    public async Task PersistTask()
    {
        var resultTask = Task.Run(() =>
        {
            Thread.Sleep(3000);
            Console.WriteLine("First");
            return Task.FromResult(0);
        });

        await resultTask;
    }
}

Between the Approach 1 and Approach 2; I prefer the Approach 1. Is there any other better way to call PersistTask() from OrderForm_Load() method? I have a colleague who is hesitant to use Task.Run but want to find out if there is any other better way.

The objective is, we want "second" to be printed ASAP and need not to worry about the method that prints "first". Fire and Forget.

Ravi Ganesan
  • 277
  • 6
  • 11
  • Really bad Fire and Forget, `public async void PersistTask` – johnny 5 Oct 04 '17 at 00:18
  • Thanks, I like how you replaced Task with Void from the signature of PersistTask. but the question which is the best approach to invoke PersistTask from OrderForm_Load() method. – Ravi Ganesan Oct 04 '17 at 00:57
  • yeah that's why I didn't post an answer. I also forgot to mention it's really bad because of silent crashes. – johnny 5 Oct 04 '17 at 01:08
  • Which is bad bcoz of silent crashes? – Ravi Ganesan Oct 04 '17 at 01:16
  • Yeah if you decide to use them you should read [this](https://haacked.com/archive/2014/11/11/async-void-methods/) first – johnny 5 Oct 04 '17 at 01:18
  • I see, the article says "Avoid async void methods" – Ravi Ganesan Oct 04 '17 at 01:41
  • They are horribly bad, except for rare cases that you need true fire and forget – Camilo Terevinto Oct 04 '17 at 10:31
  • You can allow _"second" to be printed ASAP_ by awaiting `PersistTask` after printing "second". If you don't need to _worry about the method that prints "first"_ then why even call it? Not calling the method is equivalent to the method failing every time which is acceptable if it is fire and forget so why even bother? – JSteward Oct 04 '17 at 14:41
  • Not worried about "first" referes to not worrying about its response but we need to call it. its a one way data persistence. – Ravi Ganesan Oct 04 '17 at 15:56

1 Answers1

3

The best way to achieve fire and forget methods are with the async void modifiers:

public async void PersistTask()
{
    // no need to assign the task if you are just going to await for it.
    await Task.Run(() =>
    {
        Thread.Sleep(3000);
        Console.WriteLine("First");
        return Task.FromResult(0);
    });
}

And call it using:

//Blocking
public void OrderForm_Load()
{
    var t1 = new ServiceTask();

    Task.Run(() => t1.PersistTask()); //Approach 1
    //[OR]            
    t1.PersistTask(); //Approach 2
    Console.WriteLine("Second");
}

There's another difference, though: Task.Run is best suited for CPU-bound methods. See many more details in this answer.
Also, note that you should avoid using synchronous waits in asynchronous work. So, change this:

Thread.Sleep(3000);

For this:

Task.Delay(3000);
Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • Thanks, the PersistTask is just to mimic I/O operation. await Task.Run(() => { Thread.Sleep(3000); Console.WriteLine("First"); return Task.FromResult(0); }); or assigning to a Task isnt a problem but which approach is better. So far what I read and what you suggested it is Task.Run – Ravi Ganesan Oct 04 '17 at 00:47