my program has 3 warnings of the following statement:
This async method lacks 'await' operators and will run synchronously.
Consider using the 'await' operator to await non-blocking API calls,
or 'await Task.Run(...)' to do CPU-bound work on a background thread.
What is the warning try to tell me? What should I do?
This is my code: Is it running using multi-threading?
static void Main(string[] args)
{
Task task1 = new Task(Work1);
Task task2 = new Task(Work2);
Task task3 = new Task(Work3);
task1.Start();
task2.Start();
task3.Start();
Console.ReadKey();
}
static async void Work1()
{
Console.WriteLine("10 started");
Thread.Sleep(10000);
Console.WriteLine("10 completed");
}
static async void Work2()
{
Console.WriteLine("3 started");
Thread.Sleep(3000);
Console.WriteLine("3 completed");
}
static async void Work3()
{
Console.WriteLine("5 started");
Thread.Sleep(5000);
Console.WriteLine("5 completed");
}
The async keyword, by itself, doesn't really do much. Remove it from your code and your code will act exactly the same.
What does async do?
It changes what's valid inside of the method, specifically it allows you to use the await keyword
In turn, it means that the body of the method will be transformed, based on the awaits that are present in the body of the method.
And if the method returns a value, the method is also transformed to wrap the return value in a Task.
However, if you a) Don't have any awaits in your method body and b) are void returning, then nothing special will be achieved. The compiler warning does try to be clear about this - an async method without any awaits just plain doesn't make sense. awaits are the more important part of this feature.
If you are overriding an async method with a sync method you can:
await Task.Run(() => [YOUR SYNC METHOD]);
You have used 'async' keyword with method which indicates that Work1(),Work2() and Work3() methods are executed asynchronously,but you have not used 'await' keyword.So it executed as synchronously.Use 'await' keyword if you want to execute it asynchronously.
static async void Work1()
{
Console.WriteLine("10 started");
await Task.Delay(10000);
Console.WriteLine("10 completed");
}
static async void Work2()
{
Console.WriteLine("3 started");
await Task.Delay(3000);
Console.WriteLine("3 completed");
}
static async void Work3()
{
Console.WriteLine("5 started");
await Task.Delay(5000);
Console.WriteLine("5 completed");
}
Yes, your code will probably use multi-threading. However, it would still do so if you just removed the async keyword. As you did not explain why it's there, I suggest removing it.
If you want an async/await pattern, you can use Task.Delay() but I would suggest you read more on async/await before using it:
static async void Work3()
{
Console.WriteLine("5 started");
await Task.Delay(5000);
Console.WriteLine("5 completed");
}
You designated your methods (Work1, Work2, Work3) with the keyword async but none of your code within those methods uses the await operator to invoke asynchronous calls.
Related
I'm attempting to show that it is possible for my team to add asynchronous functionality to a currently "fully-syncrhonous" program. Are there any reasons, such as requiring the async decorator, that the following code would not yield expected results if something similar were shoved into our production code?
Code:
static void Main(string[] args)
{
//TODO: Try to show that Tasks are async inside of sync methods
var waitForStuff = Task.Run(() => stuff());
Thread.Sleep(1000);
Console.WriteLine("In between stuff- From Main");
//waitForStuff.Wait(); - This wait doesn't even appear to be necessary
var result = waitForStuff.Result;
if (result == null)
{
result = "Main didn't wait for task";
}
Console.WriteLine(result);
}
private static string stuff(){
Console.WriteLine("Beginning of Stuff");
Thread.Sleep(5000);
Console.WriteLine("End of Stuff");
return "stuff";
}
Console:
Beginning of Stuff
In between stuff- From Main
End of Stuff
stuff
What do you mean by "asynchronous functionality" and "expected results"?
Your code waits for the result of a non-async method because the type it's returning (Task) is awaitable. But it isn't using the normal task asynchronous pattern and the async / await keywords.
The async keyword applied to a method enables the await keyword in that method. Then the await keyword examines the awaitable (eg Task) argument. If the awaitable has completed, the method just runs synchronously. If the awaitable hasn't completed, the method returns immediately but tells the awaitable to run the rest of the method after task completion.
So in your context:
var waitForStuff = Stuff();
public async Task<string> Stuff()
{
Console.WriteLine("Beginning of Stuff");
await Task.Delay(5000);
Console.WriteLine("End of Stuff");
return "stuff";
}
You should be aware of how to use async/await properly in console programs.
I have four methods.
Main: only calls the preform method
Working: displays "please wait for the user"
Taking Time: A program that takes time to execute.
Preform: Calls the taking time and working methods asynchronously.
The following is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncObservation
{
class Program
{
static void Main(string[] args)
{
preform();
}
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
Thread.Sleep(1000);
Console.WriteLine("The Program finished");
}
public static async void preform()
{
Task timer = Takingtime();
Task wait = Working();
}
}
}
In the end: I need to display
This program started.
Please wait, the program is running
The program ended.
I see several problems in your program.
Although Preform is neither async nor an event handler, it does not return a Task
The tasks started in Preform are not awaited for before you finish Preform. Hence you never know when they are finished, nor what the results are (exception?). You could even end your program before they are finished
After you start a Task it is not guaranteed when it will run. You can only be sure that statements are already executed if you await for the Task.
Using async-await is a method to make sure that your thread looks around to see if it can do useful stuff instead of waiting idly if it has to wait for something. Thread.Sleep is a busy wait. If you want to look around to see if you can do something else use await Task.Delay(TimeSpan.FromSeconds(1)) instead.
In your case, you can't be sure that any Console line has been written until you await the procedure that should write your line. If you start your second Task before awaiting the first, you don't know how far the first task already proceeded, and thus you don't know for sure that the text already has been written to the Console.
C# 7.1 introduced async Task Main(), so you could use that instead of the traditional void Main. It saves you from catching and interpreting the AggregateException that is thrown by the Task you start to make your process async.
If you don't want to use the async Main, you can of course use Task.Run to call an async function:
static void Main(string[] args)
{
try
{
var preformTask = Task.Run( () => Preform() );
DoSomethingElse(); // if needed
preformTask.Wait(); // wait for preformTask to finish
Console.WriteLine("Task completed; press any key to finish");
Console.ReadKey();
}
catch (Exception exc) // inclusive ggregateException if one of your Task fails
{
ProcessException(exc)
}
}
static async Task preform()
{
// To be certain that the Console Line has been written: await
await Takingtime();
// if here, you are certain that the Line has been written,
// or course you have lost parallel processing
await Working();
}
For completeness: the other functions
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
// either return a completed Task, or await for it (there is a difference!
await Task.CompletedTask;
// or:
return Task.CompletedTask; // do not declare async in this case
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
//Use Task.Delay instead of Sleep
await Task.Delay(TimeSpan.FromSeconds(1); // improved readability
Console.WriteLine("The Program finished");
}
Because of the awaits in Preform you are certain that the text has been written. However, you've lost some parallellism.
If you really want those procedures to execute at the same time, you can't be certain about when text will be written. If that is important, then split the Parts that should be run first (write Console) from the parts that should run in parallel (Task.Delay)
static async Task preform()
{
// Do the things that should be done before parallel tasks are run
await DoThisFirst();
// start the Tasks that can work parallel: not sure what statements are executed first
var taskA = DoTaskA();
var taskB = DoTaskB();
// if here, you are free to do something else
// can't be sure about the status of taskA nor taskB
DoSomethingElse();
// if you want to do something after you know that the tasks have completed:
// await the tasks here:
await Task.When (new Task[] {taskA, taskB});
// if here, you are certain that all parallel tasks have completed successfully
// if desired fetch the return values of the Tasks:
var returnValueA = taskA.Result;
var returnValueB = taskB.Result;
// do all async things of which you needed to be certain that both tasks finished
// for example:
await ProcessResults(returnValueA, returnValueB);
}
In a console app it is OK to use a .Wait() call in an void Main method.
In some contexts where there is synchronisation necessary .Wait() can cause deadlocks (ASP.NET has a request to synchronise on or XAML/WinForms which have a UI thread), but there is nothing to synchronise on here.
static void Main()
{
preform.Wait()
}
This will wait for the async work to complete synchronously. You need the method to run synchronously so that it does not return early. If you use async void and await the method will return immediately and exit the method, await does not work in a Main method.
I would also suggest using await Task.Delay(1000); rather than Thread.Sleep(1000); as this is the canonical async way to idle.
For your code example:
class Program
{
static void Main(string[] args)
{
preform().Wait();
Console.ReadLine();
}
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
await Task.Delay(1000);
Console.WriteLine("The Program finished");
}
public static Task preform()
{
return Task.WhenAll(
Takingtime(),
Working());
}
}
Use Stephen Cleary's Nito.AsyncEx library (available via Nuget) to provide an asynchronous context for a console application. See here for more details.
Your application can then be written as ...
class Program
{
static int Main(string[] args)
{
try
{
Console.WriteLine("The application has started");
AsyncContext.Run(() => LongRunningTaskAsync(args));
Console.WriteLine("The application has finished");
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return -1;
}
}
static async Task LongRunningTaskAsync(string[] args)
{
Console.WriteLine("The long running task has started");
// use Task.Delay() rather than Thread.Sleep() to avoid blocking the application
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
Console.WriteLine("The long running task has finished");
}
}
Use preform().Wait() in the constructor. So the call is awaited. Then use await Takingtime() and await Working() in the preform method.
And you have to change the return type to Task.
Do both methods below behave the same way? Is there an internal difference as to how they work? Both methods will release the UI thread and continue executing once the delay is over.
public async Task DoSomethingAsync()
{
Console.WriteLine("Test Async start");
//Any long running operation
await Task.Delay(5000);
Console.WriteLine("Test Async end");
}
public void TestTask()
{
Console.WriteLine("Test Task start");
Task.Run(() =>
{
//Any long running operation
Thread.Sleep(10000);
}
).ContinueWith((prevTask) =>
{
Console.WriteLine("Test Task end");
});
}
**output**:
Test Async start
Test Task start
Test Async end
Test Task end
Asynchronous programming with async and await
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active.
You don't need System.Threading for Tasks. The code below does because of CancellationToken.
One difference is with Task you have access to properties on the main (UI) thread.
See Quantity. You can even write to the main thread but probably not a good practice.
async Task<int> TaskDelayAsync(CancellationToken ct, IProgress<int> progress)
{
Debug.WriteLine(Quantity);
int i = 0;
while (true)
{
i++;
//Debug.WriteLine(i);
progress.Report(i);
ct.ThrowIfCancellationRequested();
await Task.Delay(500);
}
return i;
}
I'm running a test that should be calling a method multiple times without waiting for its result. Here's my code:
private async Task HandleJob(string params) {
// do stuff that takes a minute
Thread.Sleep(10000);
return;
}
[TestMethod]
public async Task StartTest() {
HandleJob("one");
HandleJob("two");
}
When I set a break at HandleJob("two"), it only gets hit after one has been completed. How do I make them run asynchronously, so no waiting is done?
You haven't used await in the method at all. This means that the method will execute the lines synchronously. To actually yield back to the caller and let the remaining code run asynchronously, you need to use await, which will continue the method as a continuation on the targeted Task (as well as unboxing any exceptions and return values)
There are a couple of helper methods in Task to assist with this - my favorite is Task.Yield(), which will immediately return, thus an await Task.Yield() will spit out into a new thread and return all at once.
[TestMethod]
public async Task StartTest() {
await Task.Yield(); // await yields control, and Yield will ensure the rest of the method starts immediately
HandleJob("one");
HandleJob("two");
}
If you want the individual subtasks to execute all at once, conglomerate them using Task.WhenAll and Task.Run
[TestMethod]
public async Task StartTest() {
await Task.WhenAll(
Task.Run(() => HandleJob("one")),
Task.Run(() => HandleJob("two")));
}
Your asynchronous method HandleJob is not really async as Thread.Sleep blocks the current thread. Try using await Task.Delay instead. Note that params is a keyword and your original code won't compile. I've changed it to parameters.
private async Task HandleJob(string parameters) {
// do stuff that takes a minute
await Task.Delay(10000);
return;
}
In your start method you can return a single Task that gets completed when both methods are finished using Task.WhenAll as pointed out in one of the other answers. If you return the result rather than await it, then the caller of StartTest can determine whether he waits for the Task to complete or if he ignores it and it becomes a fire and forget situation. Because you are not using await StartTest will not need to be marked as async anymore.
[TestMethod]
public Task StartTest() {
return Task.WhenAll(HandleJob("one"), HandleJob("two"));
}
you need to await both the tasks:
private void HandleJob( params string[] value )
{
return;
}
[TestMethod]
public async Task StartTest()
{
var task1 = Task.Run( () => HandleJob( "one" ) );
var task2 = Task.Run( () => HandleJob( "two" ) );
await Task.WhenAll( task1 , task2 );
}
Lets say I have this code:
public async void Init(){
init1();
init2();
init3();
}
First question is are they running asynchronously or not? The methods themselves are public void not async.
Second question is how do I make sure they're running async and to know when they're finished? Like this..
public async void Init(){
init1();
init2();
init3();
await ... all finished
}
Third, when I call Init() elsewhere, can it not be wrapped by an async method? Like this code below, or does it have to be async?
public async void Init(){
init1();
init2();
init3();
}
public void doIt(){
Init();
}
I have an async intro that should help.
First question is are they running asynchronously or not?
No, and you didn't really need to ask this on Stack Overflow because the compiler itself will give you a warning that explicitly states your method will run synchronously.
Second question is how do I make sure they're running async and to know when they're finished?
First, your methods need to be properly asynchronous:
async Task init1Async();
async Task init2Async();
async Task init3Async();
Then you can make the caller invoke them concurrently and then asynchronously wait for them all to complete:
async Task InitAsync() {
var task1 = init1Async();
var task2 = init2Async();
var task3 = init3Async();
await Task.WhenAll(task1, task2, task3);
}
Third, when I call Init() elsewhere, can it not be wrapped by an async method?
Once your InitAsync method is properly defined as returning a Task, it can be naturally consumed using await:
async Task doItAsync() {
await InitAsync();
}
Note that this does require the caller to be async.
Also recommended reading: my Best Practices for Asynchronous Code MSDN article, particularly the sections on "avoid async void" and "async all the way".
Also One Thing you can do await on each on the methods to get the required result of each methods.
var task1 = await init1Async();
var task2 = await init2Async();
var task3 = await init3Async();