-2

I have some IO-Bound jobs(periodically write some data to file) codes as follows:

public async Task SaveToFile1(int sleepTimeout)
{
     while (true)
     {
        // Do file saving work
        await Task.Delay(sleepTimeout).ConfigureAwait(false);
     }
}

public async Task SaveToFile2(int sleepTimeout)
{
    while (true)
    {
        // Do file saving work
        await Task.Delay(sleepTimeout).ConfigureAwait(false);
    }
}

public async Task SaveToFile3(int sleepTimeout)
{
    while (true)
    {
        // Do file saving work
        await Task.Delay(sleepTimeout).ConfigureAwait(false);
    }
}

The caller is the main method. The tasks worked fine and produced the correct result when I run them with 2 ways as follows:

void main () 
{
    // other codes

    // way 1:
    SaveToFile1(1000);
    SaveToFile2(1000);
    SaveToFile3(1000);

    // other codes will not let the app exit
}
void main () 
{
    // other codes

    // way 2:
    Task.Run(async() => await SaveToFile1(1000));
    Task.Run(async() => await SaveToFile2(1000));
    Task.Run(async() => await SaveToFile3(1000));

    // other codes will not let the app exit
}

Which is the right way or another way is the best choice for my situation?

Thanks for your answers!


Edit:

In way 1, when await Task.Delay 'complete', a new thread-pool thread may be captured to execute the loop's next step, ..., loop will always running in other thread at the await hit.

In way 2, may be a new thread-pool thread will be used when Task.Run execute immediately, loop will always running in other thread at the begin.

The result are the same, where is the diffrence?

So my question is not about Task.Run vs async-await!

Jeffrey Hill
  • 167
  • 1
  • 9
  • 1
    *Which is right way* [**non**](https://dotnetfiddle.net/BXR1IS) – Selvin Nov 28 '19 at 03:31
  • 1
    That's _"I/O code"_? Looks like a whole lot of sleeps to me –  Nov 28 '19 at 03:37
  • @Selvin please add Console.ReadKey(); at the end of main, I have some blocks code in real environment. Since dotnetfiddle does not support loop codes, you should use a real console app. – Jeffrey Hill Nov 28 '19 at 03:40
  • @MickyD There are some IO Code before next sleep. – Jeffrey Hill Nov 28 '19 at 04:14
  • _"The result are the same, where is the diffrence?"_ -- you've already identified the difference yourself: using `Task.Run()` causes the initial execution of your `async` method to occur in a thread pool thread instead of the current one. This may or may not be significant, depending on how long that initial code takes. The marked duplicates also have answers explaining this exact difference. It is the only material one, IMO. If it weren't for that, I'd say never use `Task.Run()` with an async method. And many if not most async methods are designed to reach the first await ASAP. – Peter Duniho Nov 28 '19 at 04:50

1 Answers1

1

Asynchronous code allows the current thread to be freed to do other work while waiting for a response from something else. But all the code before the first await will be done on the same thread you call it from. If that code is significantly CPU-heavy, it could be noticeable.

If you don't use Task.Run, the method will be run on the same thread up until the first asynchronous I/O request, when it will return a Task and your next method will be called.

Task.Run will execute the code on a different thread. This is good if it does do some CPU-heavy work and you don't want that done on the current thread (like in a desktop app where you don't want it done on the UI thread). But there is a small cost to starting up a new thread too.

Whether using Task.Run will make any noticeable difference depends on the type of app you're writing and what your methods do.

It's fine if you don't await them immediately, but if you don't ever await them, then you will never know when they finished, if they finished successfully, or threw and exception. This is called "fire and forget". Do that only if you don't care if they succeed.

Instead, you can wait at the end to make sure they completed successfully. For example:

void main () 
{
    // other codes

    var taskList = new List<Task>();
    taskList.Add(SaveToFile1(1000));
    taskList.Add(SaveToFile2(1000));
    taskList.Add(SaveToFile3(1000));

    // other codes will not let the app exit

    // wait till everything finishes before exiting
    await Task.WhenAll(taskList);
}
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84