Based on following code, my expectation was that console would emit
SayTaskHelloCalled
Task Executing
SayHelloAfterSleepTask
But task doesn't runs. Only first line emits in console. Please suggest why?
static void Main(string[] args)
{
var task2 = SayHelloTask();
var result = task2.Result;
Console.WriteLine(result);
}
public static Task<string> SayHelloTask()
{
Thread.Sleep(2000);
Console.WriteLine("SayHelloTaskCalled");
return new Task<string>(() => {
Console.WriteLine("Task Executing");
return "SayHelloAfterSleepTask";
});
Creating a new Task using its one of the constructors hands you back a "Cold Task". Meaning that the Task isn't started yet. Since you've never started the Task, you don't see the expected output.
You need to call Task.Start to start it. In order to return a "Hot Task"(Started Task), you need to use Task.Factory.StartNew or Task.Run.
Following should work:
public static Task<string> SayHelloTask()
{
Thread.Sleep(2000);
Console.WriteLine("SayHelloTaskCalled");
return Task.Run(() => {
Console.WriteLine("Task Executing");
return "SayHelloAfterSleepTask";
});
}
If you prefer your Task to be the "Cold Task" itself, then modify your calling code as below.
static void Main(string[] args)
{
var task2 = SayHelloTask();
task2.Start();//<--Start a "Cold task"
var result = task2.Result;
Console.WriteLine(result);
}
Related
I create a Task variable and try to await it just for learning purposes with the next code:
static async Task Main(string[] args)
{
Console.WriteLine("Start");
Task myTask = new Task(() => { Console.WriteLine("Done"); });
await myTask;
Console.WriteLine("Finish");
}
Application writes Start in the console and then it freezes. I am not sure how to understand whats happened here and why does it freeze. What can be the reason?
I know that usually we apply await to the methods which return Task, but not variable. But vs compiles such code successfully. The expectation was to get all 3 messages in the console.
new Task() creates a new task instance, but does not start it.
so your task never runs, and never has a chance to finish. to fix it you, have to start it first:
static async Task Main(string[] args)
{
Console.WriteLine("Start");
Task myTask = new Task(() => { Console.WriteLine("Done"); });
myTask.Start();
await myTask;
Console.WriteLine("Finish");
}
i also recommend reading Microsofts Tutorial on tasks
Do not ever use the Task constructor (link is to my blog). There are literally zero use cases for it that aren't achieved by better means.
If you want to start work running on the thread pool, then use Task.Run:
static async Task Main(string[] args)
{
Console.WriteLine("Start");
Task myTask = Task.Run(() => { Console.WriteLine("Done"); });
await myTask;
Console.WriteLine("Finish");
}
In an answer to one of my other questions, I was told that use of new Task(() => { }) is not something that is a normal use case. I was advised to use Func<Task> instead. I have tried to make that work, but I can't seem to figure it out. (Rather than drag it out in the comments, I am asking a separate question here.)
My specific scenario is that I need the Task to not start right when it is declared and to be able to wait for it later.
Here is a LinqPad example using new Task(() => { }). NOTE: This works perfectly! (Except that it uses new Task.)
static async void Main(string[] args)
{
// Line that I need to swap to a Func<Task> somehow.
// note that this is "cold" not started task
Task startupDone = new Task(() => { });
var runTask = DoStuff(() =>
{
//+++ This is where we want to task to "start"
startupDone.Start();
});
//+++ Here we wait for the task to possibly start and finish. Or timeout.
// Note that this times out at 1000ms even if "blocking = 10000" below.
var didStartup = startupDone.Wait(1000);
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
await runTask;
Console.Read();
}
public static async Task DoStuff(Action action)
{
// Swap to 1000 to simulate starting up blocking
var blocking = 1; //1000;
await Task.Delay(500 + blocking);
action();
// Do the rest of the stuff...
await Task.Delay(1000);
}
I tried swapping the second line with:
Func<Task> startupDone = new Func<Task>(async () => { });
But then the lines below the comments with +++ in them don't work right.
I swapped the startupDone.Start() with startupDone.Invoke().
But startupDone.Wait needs the task. Which is only returned in the lambda. I am not sure how to get access to the task outside the lambda so I can Wait for it.
How can use a Func<Task> and start it in one part of my code and do a Wait for it in another part of my code? (Like I can with new Task(() => { })).
The code you posted cannot be refactored to make use of a Func<Task> instead of a cold task, because the method that needs to await the task (the Main method) is not the same method that controls the creation/starting of the task (the lambda parameter of the DoStuff method). This could make the use of the Task constructor legitimate in this case, depending on whether the design decision to delegate the starting of the task to a lambda is justified. In this particular example the startupDone is used as a synchronization primitive, to signal that a condition has been met and the program can continue. This could be achieved equally well by using a specialized synchronization primitive, like for example a SemaphoreSlim:
static async Task Main(string[] args)
{
var startupSemaphore = new SemaphoreSlim(0);
Task runTask = RunAsync(startupSemaphore);
bool startupFinished = await startupSemaphore.WaitAsync(1000);
Console.WriteLine(startupFinished ? "Startup Finished" : "Startup Timed Out");
await runTask;
}
public static async Task RunAsync(SemaphoreSlim startupSemaphore)
{
await Task.Delay(500);
startupSemaphore.Release(); // Signal that the startup is done
await Task.Delay(1000);
}
In my opinion using a SemaphoreSlim is more meaningful in this case, and makes the intent of the code clearer. It also allows to await asynchronously the signal with a timeout WaitAsync(Int32), which is not something that you get from a Task out of the box (it is doable though).
Using cold tasks may be tempting in some cases, but when you revisit your code after a month or two you'll find yourself confused, because of how rare and unexpected is to have to deal with tasks that may or may have not been started yet.
I always try my hardest to never have blocking behavior when dealing with anything async or any type that represents potential async behavior such as Task. You can slightly modify your DoStuff to facilitate waiting on your Action.
static async void Main(string[] args)
{
Func<CancellationToken,Task> startupTask = async(token)=>
{
Console.WriteLine("Waiting");
await Task.Delay(3000, token);
Console.WriteLine("Completed");
};
using var source = new CancellationTokenSource(2000);
var runTask = DoStuff(() => startupTask(source.Token), source.Token);
var didStartup = await runTask;
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
Console.Read();
}
public static async Task<bool> DoStuff(Func<Task> action, CancellationToken token)
{
var blocking = 10000;
try
{
await Task.Delay(500 + blocking, token);
await action();
}
catch(TaskCanceledException ex)
{
return false;
}
await Task.Delay(1000);
return true;
}
First, the type of your "do this later" object is going to become Func<Task>. Then, when the task is started (by invoking the function), you get back a Task that represents the operation:
static async void Main(string[] args)
{
Func<Task> startupDoneDelegate = async () => { };
Task startupDoneTask = null;
var runTask = await DoStuff(() =>
{
startupDoneTask = startupDoneDelegate();
});
var didStartup = startupDoneTask.Wait(1000);
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
}
I was reading this doc https://learn.microsoft.com/en-us/dotnet/csharp/async which says that:
For I/O-bound code, you await an operation which returns a Task or Task inside of an async method.
I have two questions:
Q1- for I/O-bound code, does it mean we need to use Task.Factory.StartNew(..., TaskCreationOptions.LongRunning) or TaskCompletionSource
Q2- I wrote a two simple console apps below to simulate I/O-bound code, is my approach correct?
class Program //use Task.Factory.StartNew
{
static async Task Main(string[] args)
{
var task = ReadFile();
Console.WriteLine("Do other work");
int total = await task;
Console.WriteLine($"Read {total} lines");
Console.ReadLine();
}
static async Task<int> ReadFile()
{
return await Task.Factory.StartNew(new Func<int>(Read), TaskCreationOptions.LongRunning);
}
static int Read()
{
Thread.Sleep(5000); // simulate read operation
return 9999; // 9999 lines has been read
}
}
and
class Program // use TaskCompletionSource
{
static void Main(string[] args)
{
var awaiter = ReadFile().GetAwaiter();
Console.WriteLine("Do other work");
awaiter.OnCompleted(() => Console.WriteLine($"Read {awaiter.GetResult()} lines"));
Console.ReadLine();
}
static Task<int> ReadFile()
{
var tcs = new TaskCompletionSource<int>();
new Thread(() =>
{
tcs.SetResult(Read());
}).Start();
return tcs.Task;
}
static int Read()
{
Thread.Sleep(5000); // simulate read operation
return 9999; // 9999 lines has been read
}
}
Q1- for I/O-bound code, does it mean we need to use Task.Factory.StartNew(..., TaskCreationOptions.LongRunning) or TaskCompletionSource
No.
It means you use async and await.
Q2- I wrote a two simple console apps below to simulate I/O-bound code, is my approach correct?
No.
I/O is not synchronous by nature, so using Thread.Sleep is an incorrect substitute for I/O work. I/O is asynchronous by nature, so the proper placeholder is await Task.Delay.
class Program // use async/await
{
static async Task Main(string[] args)
{
var task = ReadFileAsync();
Console.WriteLine("Do other work");
var result = await task;
Console.WriteLine($"Read {result} lines");
Console.ReadLine();
}
static async Task<int> ReadFileAsync()
{
await Task.Delay(5000); // simulate read operation
return 9999; // 9999 lines has been read
}
}
In the general I/O case, there is no thread. This is why using Thread.Sleep throws everything off; it forces a thread to be used, when I/O doesn't need one.
Async beginner here, trying to improve this skill.
I want to execute a method at most every 500 miliseconds, or longer if a given execution takes longer than that. In that case the loop can continue imediately.
I know that I could do that with a StopWatch or some other timer, but I would like to do that with async/await constructs.
I developed a quick spike, but when I run it it seems to execute very tightly, and not once very 500ms or more. What am I forgeting to "await"?
class Program
{
static void Main(string[] args)
{
while (true)
{
Run();
}
}
static async void Run()
{
var task1 = Task.Delay(500);
var task2 = DoSomethingAsync();
await Task.WhenAll(task1, task2);
}
static async Task DoSomethingAsync()
{
Random r = new Random();
int miliseconds = Convert.ToInt32(r.NextDouble() * 1000);
await Task.Delay(miliseconds);
Console.WriteLine(miliseconds);
}
}
You do not await the toplevel task (Since you do not have one). Try this:
class Program
{
static void Main(string[] args)
{
while (true)
{
Run().Wait(); // Wait on each iteration.
}
}
// Need to return Task to be able to await it.
static async Task Run()
{
var task1 = Task.Delay(500);
var task2 = DoSomethingAsync();
await Task.WhenAll(task1, task2);
}
static async Task DoSomethingAsync()
{
Random r = new Random();
int miliseconds = Convert.ToInt32(r.NextDouble() * 1000);
await Task.Delay(miliseconds);
Console.WriteLine(miliseconds);
}
}
Now, there is a catch in using .Wait(): it blocks execution. See this excellent guide: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx for more details. But don't worry, for the Main method of a Console App it is perfectly safe.
The same guide explains also why you should always try to return a Task instead of using async void MyTask() { ... }. In your case it prevents you from waiting for the Run() method to complete.
I have a DLL which has public Task<> method which returns return Task.Factory.StartNew(() => ...). I am calling it within a program and I want the program to wait for the execution of the task to finish before it continues doing other things. I've added Thread.Sleep(6000) to the DLL to simulate longer execution.
When I'm calling it like this
var invokedTask = myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
It just continues with execution (as expected). But then I tried this:
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
And it doesn't work. How can I make it wait from outside of DLL?
Just Wait for the task that is being returned - don't spin up another Task just to call the original method:
var invokedTask = (Task)myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
invokedTask.Wait();
I think the calling method must have the async keyword in the definition:
async void (or Task) MyCaller()
{
await Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
}
void or Task depends on which context you are in.
When you wait() a Task.Factory.StartNew() the result is a Task
Therefore you have to call wait() two times or you can use await operator.
Therefore you can do the following.
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
var result=await await invokedTask;
Or you can do the following
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
var resultTask=invokedTask.Result;
resultTask.Wait();
var result=resultTask.Result;
However from the question you have posted, it looks like your myMethod.Invoke() returns Task.Factor.StartNew() therefore I would like you to try
var result =await await myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
However it is a bad practice to use Wait() and then Result() as it block the current thread.
Therefore I would like you to use await.
This example may help:
public class MagicClass
{
private int magicBaseValue;
public MagicClass()
{
magicBaseValue = 9;
}
public Task<int> ItsMagic(int preMagic)
{
return Task.Factory.StartNew(() => preMagic * magicBaseValue);
}
}
public class TestMethodInfo
{
public static void Main()
{
// Get the ItsMagic method and invoke with a parameter value of 100
Type magicType = typeof(MagicClass);
MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
var magicValue = ((Task<int>)(magicMethod.Invoke(Activator.CreateInstance(typeof(MagicClass)), new object[] { 100 }))).Result;
Console.WriteLine("MethodInfo.Invoke() Example\n");
Console.WriteLine("MagicClass.ItsMagic() returned: {0}", magicValue.ToString());
Console.ReadKey();
}
}
You can cast your Invoke as a Task<> and then get the Result. This will wait until the method is done executing.