using System;
using System.Threading.Tasks;
namespace _1._8_Starting_A_New_Task
{
public static class Program
{
public static void Main()
{
Task t = new Task(() =>
{
for (int x = 0; x < 100; x++)
{
Console.Write('*');
}
});
t.Wait();
}
}
}
This application compiles and runs displaying a blank screen (waiting on the task to complete)
The task stays in a waiting state
No output is displayed/written to console
Why not?
Application stays in "wait" state permanently
Why?
Goal of code: Start a new task, wait for task to complete, exit application
Because you never start the Task. Using the Task constructor requires you to call Task.Start on the returned task. This is why it's recommended to use Task.Run instead, which returns a "Hot task" (a task which has started):
The documentation:
Rather than calling this constructor, the most common way to
instantiate a Task object and launch a task is by calling the static
Task.Run(Action) or TaskFactory.StartNew(Action) method. The only
advantage offered by this constructor is that it allows object
instantiation to be separated from task invocation.
So the code should be:
public static void Main()
{
Task t = Task.Run(() =>
{
for (int x = 0; x < 100; x++)
{
Console.Write('*');
}
});
t.Wait();
}
Related
I'm trying to use the Polly library to monitor/restart tasks that fail. However, I'm having a difficult time keeping the same input arguments between retry attempts.
using System;
using System.IO;
using System.Collections.Generic;
using Polly;
using System.Threading.Tasks;
namespace Sampler
{
class Program
{
public static async Task Main(string[] args)
{
// create and execute policies for each sampler
List<Task> policy_list = new List<Task>();
for(int i = 0; i < 2; i++)
{
var policy = Policy
.Handle<Exception>()
.RetryForeverAsync()
.ExecuteAsync(async () => await Program.TaskMethod(i.ToString()));
policy_list.Add(policy);
}
await Task.WhenAll(policy_list.ToArray());
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
public static async Task TaskMethod(string task_id)
{
Console.WriteLine("Starting Task {0}", task_id);
while (true)
{
await Task.Delay(5000);
Console.WriteLine("Hello from task {0}", task_id);
int i = 0;
int b = 32 / i;
}
}
}
}
When I run this code, I get the following output:
Starting Task 0
Starting Task 1
Hello from task 1
Hello from task 0
Starting Task 2 // BAD! this should be starting task 0
Starting Task 2 // BAD! this should be starting task 1
Hello from task 2
Hello from task 2
Starting Task 2
Starting Task 2
The obvious issue is associated with this line:.ExecuteAsync(async () => await Program.TaskMethod(i.ToString())); I am providing the task number as a variable which is a problem because this variable goes to "2" at the end of the for loop. Thus task ID 2 is used for the remainder of retries.
So my question: How would I reformat my lambda expression such that it only references the 'i' variable once such that it maintains its original task ID?
this is called closure. Safe i in a temporary local variable:
for(int i = 0; i < 2; i++)
{
int temp = i;
var policy = Policy
.Handle<Exception>()
.RetryForeverAsync()
.ExecuteAsync(async () => await Program.TaskMethod(temp.ToString()));
policy_list.Add(policy);
}
Here is a nice article that explains it far better then I ever could in here.
I've been reading the following post, specifically this point:
On your application’s entry point method, e.g. Main. When you await an instance that’s not yet completed, execution returns to the caller of the method. In the case of Main, this would return out of Main, effectively ending the program.
I've been trying to do that, but I can't seem to make it exit. Here's the code I have:
class Program
{
// ending main!!!
static async Task Main(string[] args)
{
Task<Task<string>> t = new Task<Task<string>>(async () =>
{
Console.WriteLine("Synchronous");
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Synchronous");
Console.WriteLine("Synchronous I is: " + i);
await Task.Run(() => { Console.WriteLine("Asynchronous"); });
await Task.Run(() => { for (int j = 0; j < 1000; j++) { Console.WriteLine( "Asynchronous, program should have exited by now?"); }});
}
return "ASD";
});
t.Start();
await t;
}
}
What exactly am I missing here? Shouldn't the program exit upon hitting the line await t; or by following through the thread at await Task.Run(() => { Console.WriteLine("Asynchronous"); });?
This is a Console application's main method.
The article you linked is from 2012, which predates the addition of async support to Main(), which is why what it's talking about seems wrong.
For the current implementation, consider the following code:
public static async Task Main()
{
Console.WriteLine("Awaiting");
await Task.Delay(2000);
Console.WriteLine("Awaited");
}
This gets converted by the compiler as follows (I used "JustDecompile" to decompile this):
private static void <Main>()
{
Program.Main().GetAwaiter().GetResult();
}
public static async Task Main()
{
Console.WriteLine("Awaiting");
await Task.Delay(2000);
Console.WriteLine("Awaited");
}
Now you can see why the program doesn't exit.
The async Task Main() gets called from static void <Main>() which waits for the Task returned from async Task Main() to complete (by accessing .GetResult()) before the program exits.
I have a simple program to test async/await, 2 versions: version 1 awaits another method inside async function, version doesn't:
Program 1:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main starts..");
AsyncMethod();
Thread.Sleep(1000);
Console.WriteLine("main ends..");
Console.ReadLine();
}
static async void AsyncMethod()
{
Console.WriteLine("async starts");
var result = await MyMethod();
Console.WriteLine("async starts ends");
}
static async Task<int> MyMethod()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("async runs" + i.ToString() + "..");
await Task.Delay(1000);
}
return 0;
}
}
Program 2:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main starts..");
AsyncMethod();
Thread.Sleep(1000);
Console.WriteLine("main ends..");
Console.ReadLine();
}
static async void AsyncMethod()
{
Console.WriteLine("async starts");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("async runs" + i.ToString() + "..");
await Task.Delay(1000);
}
Console.WriteLine("async ends");
}
}
Both programs yields same result. I am just curious, do both program differs in what happens in the background?
I guess, program 1 will create 2 sub-threads, each level of "async" leads to a thread; program 2 will create 1 sub-thread. Right?
As long as "await" will wait until the task ends, then what's the difference from writing synchronous code? I think it just link creating several threads and call ".join()" for all of them. Right?
Both are async or Threaded programming using await means until your function execute your execution pointer will be hold on that functions it self and if you don't use wait it will pass on to next execution pointer mostly there is two reason behind adding await mostly in winform application while going for big process execution we may need to let software user to do the other work in the same form then we need to await the task. or some times we need get some data from one method so the method should be finished and next logic should execute in a new or other thread.
I'm puzzled with this situation, where a class has a method that launches two periodic Tasks and then a property is used to check if both Tasks are still running or not, but the result is unexpected. Here is the code (simplified):
public partial class UdpClientConnector
{
Task localListener;
Task periodicSubscriber;
bool keepWorking = false;
public bool IsRunning
{
get
{
if ((localListener != null) && (periodicSubscriber != null))
{
return (localListener.Status == TaskStatus.Running) &&
(periodicSubscriber.Status == TaskStatus.Running);
}
else
return false;
}
}
public void Start()
{
keepWorking = true;
localListener = new Task(() => LocalListenerWorker());
localListener.Start();
periodicSubscriber = new Task(() => PeriodicSubscriberWorker());
periodicSubscriber.Start();
}
public void Stop()
{
keepWorking = false;
localListener.Wait();
periodicSubscriber.Wait();
}
async void LocalListenerWorker()
{
while (keepWorking)
{
// Do some work and then wait a bit
await Task.Delay(1000);
}
}
async void PeriodicSubscriberWorker()
{
while (keepWorking)
{
// Do some (other) work and then wait a bit
await Task.Delay(1000);
}
}
}
To test this boilerplate I used the following:
UdpClientConnector connector = new UdpClientConnector();
// This assert is successful because the two Tasks are not yet started
Assert.IsTrue(!connector.IsRunning);
// Starts the tasks and wait a bit
Connector.Start();
Task.Delay(2000).Wait();
// This fails
Assert.IsTrue(connector.IsRunning);
When I've tried to debug the test case, I've found that two Tasks are in the RanToCompletion state, which is unexpected due the fact that both tasks are just loops and should not terminate until keepWorking becomes false.
I've tried also to start the Tasks using Task.Factory.StartNew(..) with same results.
What I'm missing? Thank you!
The problem is with how you start the tasks, and indeed the task methods.
localListener = new Task(() => LocalListenerWorker());
That task will complete when LocalListenerWorker returns - which it will do pretty much immediately (when it hits the first await expression). It doesn't wait for the asynchronous operation to actually complete (i.e. the loop to finish).
async void methods should almost never be used - they're basically only there to support event handlers.
I suggest you rewrite your methods to return Task, and then use Task.Run to start them, passing in a method group:
Task.Run(LocalListenerWorker);
...
private async Task LocalListenerWorker()
{
// Body as before
}
The task by Task.Run will only complete when the task returned by LocalListenerWorker completes, which is when the loop body finishes.
Here's a complete demo:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Task task1 = Task.Run(Loop);
// Don't do this normally! It's just as a simple demo
// in a console app...
task1.Wait();
Console.WriteLine("First task done");
Task task2 = new Task(() => Broken());
task2.Start();
// Don't do this normally! It's just as a simple demo
// in a console app...
task2.Wait();
Console.WriteLine("Second task done");
}
static async Task Loop()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine(i);
}
}
static async void Broken()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine(i);
}
}
}
The output shows:
0
1
2
3
4
First task done
Second task done
The first task behaves as expected, and only completes when the first async method has really completed. The second task behaves like your current code: it completes as soon as the second async method has returned - which happens almost immediately due to the await.
In my code in the main thread I call a 3rd party API. For each result from the API I call 2 async tasks. Sometimes all works perfectly, sometimes not all async tasks run. I suppose that when the main thread finishes, the garbage collector kills all my other tasks that run in the background. Is there any way to tell garbage collector not to kill the background services when the main thread finishes?
The code is like this:
for (int i = 0; i < 1000; i++)
{
var demo = new AsyncAwaitTest();
demo.DoStuff1(guid);
demo.DoStuff2(guid);
}
public class AsyncAwaitTest
{
public async Task DoStuff1(string guid)
{
await Task.Run(() =>
{
DoSomething1(guid);
});
}
public async Task DoStuff2(string guid)
{
await Task.Run(() =>
{
DoSomething2(guid);
});
}
private static async Task<int> DoSomething1(string guid)
{
// insert in db or something else
return 1;
}
private static async Task<int> DoSomething2(string guid)
{
// insert in db or something else
return 1;
}
Thanks
If you want to wait for all your tasks to finish, you have to collect them and wait for them. Because when your process ends, that normally is the end of everything.
var tasks = List<Task>();
for (int i = 0; i < 1000; i++)
{
var demo = new AsyncAwaitTest();
tasks.Add(demo.DoStuff1(guid));
tasks.Add(demo.DoStuff2(guid));
}
// before your process ends, you need to make sure all tasks ave finished.
Task.WaitAll(tasks.ToArray());
You also have 2 levels of carelessness (meaning you start a task and don't care whether it's done). You need to remove the second one, too:
public async Task DoStuff1(string guid)
{
await DoSomething1(guid);
}