Please help me find the right solution.
The main problem the waiting completion of the program through the console, and at the same time monitor tasks.
I wrote some prototype, but I am not sure that is effective - in this approach, we spend an extra thread of waiting for action from the console. I do not see alternatives, since Console does not support asynchronous (some sort of Console.ReadLineAsync).
UPDATE:
I have two working Tasks (task1, task2).They simulate some real work.
The program is a console. So we need to give user a chance to stop the program.By default in consoles, this is done via the expectation of pressing "Enter" (through consoleTask).
The question is. How to wait for the completion of worker threads AND Monitor stop command from the user.
static void Main(string[] args)
{
CancellationTokenSource mycts = new CancellationTokenSource();
var task1 = Task.Run(() =>
{
// doing some work, that can throw exception
Thread.Sleep(1000);
// how to avoid this closuring ?
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}).ContinueWith((_) => mycts.Cancel()); // Do I need caching this task?
var task2 = Task.Run(() =>
{
// doing some work, that can throw exception
Thread.Sleep(5000);
// again closuring
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}).ContinueWith((_) => mycts.Cancel()); // Do I need caching this task?
// I do not know how to do better with Console !!
var consoleTask = Task.Factory.StartNew((cts) =>
{
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}, mycts).ContinueWith((_) => mycts.Cancel()); // Do I need caching this task?
// Waiting for the Completion or Exception
Task.WaitAny(task1, task2, consoleTask);
// Now waiting for the completion of workflow
try
{
Task.WaitAll(task1, task2);
}
catch (Exception ex)
{
// log faulted tasks
}
//Exit
}
There's a few guidelines you should follow:
Do not use ContinueWith. Use await instead.
Do not use Task.Factory.StartNew. Use Task.Run instead.
Do not mix blocking and asynchronous code. In the case of a console application, it's generally best to just have Main call a MainAsync and wait on the returned task. For most applications, that's the only blocking you should use.
I'm not sure what how to avoid this closuring? means.
In the case of ReadLine (and other Console methods), you are correct, there are unfortunately no asynchronous methods. It might work to use a separate thread, but the Console class (more particularly, the Console input and output streams) have some unusual locking going on under the covers, so I'm not positive this would work:
static void Main(string[] args)
{
MainAsync().Wait();
}
static CancellationTokenSource mycts = new CancellationTokenSource();
static async Task MainAsync()
{
try
{
var task1 = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => SomeWorkThatCanThrowException()));
var task2 = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => OtherWorkThatCanThrowException()));
var consoleTask = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => MonitorConsole()));
await Task.WhenAll(task1, task2, consoleTask);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void OtherWorkThatCanThrowException()
{
Thread.Sleep(5000);
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}
static void SomeWorkThatCanThrowException()
{
Thread.Sleep(1000);
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}
static void MonitorConsole()
{
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
static async Task CancelAfterSuccessfulCompletionAsync(Task task)
{
await task;
mycts.Cancel();
}
Since console doesn't have a SynchronizationContext there's not much you can do without blocking the main thread while your async operations are executing.
However, it's much simpler if you just write your code as if it's asynchronous and block in the simplest possible way. I would suggest moving all your code into an async MainAsync and blocking once:
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
// manage tasks asynchronously
}
What you can do, instead of blocking, is use a custom context for executing asynchronous operations like Stephen Cleary's AsyncContext. This allows you to avoid blocking synchronously on a Task:
static void Main()
{
AsyncContext.Run(MainAsync);
}
Related
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.
I'm trying to find out how to use WhenAll to let two methods run at once, and once they both finish, collect the results without blocking by using .Result
I have this little console app test:
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
public static void Main(string[] args)
{
var run = TaskRunner();
Debug.WriteLine(run);
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
} else
{
Debug.WriteLine("this failed!");
}
}
public static async Task<string> TaskRunner()
{
var taskOne = OneAsync();
var taskTwo = TwoAsync();
var tasks = await Task.WhenAll(taskOne, taskTwo);
var retval = tasks[0] + tasks[1];
return retval;
}
public static Task<string> OneAsync()
{
return Task.Run(() =>
{
return "test1";
});
}
public static Task<string> TwoAsync()
{
return Task.Run(() =>
{
return "test2";
});
}
}
}
This currently prints this worked! to my Output window... However, if I comment out Debug.WriteLine(run); it prints this failed!... Why does the Task complete simply by being logged to the output window?
I'm trying to understand a huge problem in a complex piece of code and this little test is my MCVE to hopefully shed some light on what is happening behind the scenes.
This happens just by pure chance. The way you are starting your task is with Task.Run. This essentially creates a new thread on which the (synchronous) action is executed. It returns a task for the completion of that thread.
So OneAsync and TwoAsync will each spawn a new thread that then immediately returns a string. This will happen very quickly but there’s still some overhead for creating those threads which means that it won’t be instantaneous.
TaskRunner then calls both those methods (spawning the threads), and then asynchronously waits for both threads to finish. Since the threads are not completely instantly, this TaskRunner method also won’t complete instantly.
Now, in your main, you are starting the asynchronous TaskRunner, which we figured will take “a very short moment”. You do not await the task, so the execution continues immediately. Debug.WriteLine is executed to print something (it probably doesn’t really matter that it’s the task in question that is being printed), and then you are checking the state of the task.
Since printing stuff is relatively slow (compared to other operations), this is probably the reason why the tasks ends up being completed. And when you remove the printing, the if is just reached too quickly for the task to finish.
As you likely noticed, working like that with asynchronous tasks does not appear to be a good idea. That’s why you should always await the task when you depend on its result.
// note the *async* here; async main methods are supported with C# 7.1
public static async void Main(string[] args)
{
var run = TaskRunner();
// await the task
await run;
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
}
else
{
Debug.WriteLine("this failed!");
}
}
I am rather new to task based programming and trying to determine how to return a task and verify that it has been started. The code that I got to work was not what I was expecting. The console application is as follows:
public static void Main(string[] args)
{
var mySimple = new Simple();
var cts = new CancellationTokenSource();
var task = mySimple.RunSomethingAsync(cts.Token);
while (task.Status != TaskStatus.RanToCompletion)
{
Console.WriteLine("Starting...");
Thread.Sleep(100);
}
Console.WriteLine("It is started");
Console.ReadKey();
cts.Cancel();
}
public class Simple
{
public async void RunSomething(CancellationToken token)
{
var count = 0;
while (true)
{
if (token.IsCancellationRequested)
{
break;
}
Console.WriteLine(count++);
await Task.Delay(TimeSpan.FromMilliseconds(1000), token).ContinueWith(task => { });
}
}
public Task RunSomethingAsync(CancellationToken token)
{
return Task.Run(() => this.RunSomething(token));
}
}
The output is:
Starting...
0
It is started
1
2
3
4
Why is the task that is being returned have a status as TaskStatus.RanToCompletion compared to TaskStatus.Running as we see that the while loop is still executing? Am I checking the status of the task of putting the RunSomething task on the threadpool rather than the RunSomething task itself?
RunSomething is an async void method, meaning it exposes no means of the caller ever determining when it finishes, they can only ever start the operation and then have no idea what happens next. You then wrap a call to it inside of Task.Run, this is schedluing a thread pool thread to start RunSomething. It will then complete as soon as it has finished starting that Task.
If RunSomething actually returned a Task, then the caller would be able to determine when it actually finished, and if you waited on it it wouldn't actually indicate that it was done until that asynchronous operation was actually finished (there would be no reason to use Task.Run to start it in another thead, you'd be better off just calling it directly and not wasting the effort of moving that to a thread pool thread).
Never use async void (https://msdn.microsoft.com/en-us/magazine/jj991977.aspx)
instead you should use async Task
If you need to call an async method from a non-async (such as from a static void main) you should do something like this:
mySimple.RunSomethingAsync(cts.Token).GetAwaiter().GetResult();
That will effectively make the method a synchronous call.
You can use async void, but only for events.
I'm still getting up to speed with async & multi threading. I'm trying to monitor when the Task I Start is still running (to show in a UI). However it's indicating that it is RanToCompletion earlier than I want, when it hits an await, even when I consider its Status as still Running.
Here is the sample I'm doing. It all seems to be centred around the await's. When it hits an await, it is then marked as RanToCompletion.
I want to keep track of the main Task which starts it all, in a way which indicates to me that it is still running all the way to the end and only RanToCompletion when it is all done, including the repo call and the WhenAll.
How can I change this to get the feedback I want about the tskProdSeeding task status?
My Console application Main method calls this:
Task tskProdSeeding;
tskProdSeeding = Task.Factory.StartNew(SeedingProd, _cts.Token);
Which the runs this:
private async void SeedingProd(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
await Task.WhenAll(Task.Run(async () =>
{
foreach (var code in codesToSeed)
{
if (!token.IsCancellationRequested)
{
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
}
}, token));
Thread.Sleep(30000);
}
}
If you use async void the outer task can't tell when the task is finished, you need to use async Task instead.
Second, once you do switch to async Task, Task.Factory.StartNew can't handle functions that return a Task, you need to switch to Task.Run(
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
Once you do both of those changes you will be able to await or do a .Wait() on tskProdSeeding and it will properly wait till all the work is done before continuing.
Please read "Async/Await - Best Practices in Asynchronous Programming" to learn more about not doing async void.
Please read "StartNew is Dangerous" to learn more about why you should not be using StartNew the way you are using it.
P.S. In SeedingProd you should switch it to use await Task.Delay(30000); insetad of Thread.Sleep(30000);, you will then not tie up a thread while it waits. If you do this you likely could drop the
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
and just make it
tskProdSeeding = SeedingProd(_cts.Token);
because the function no-longer has a blocking call inside of it.
I'm not convinced that you need a second thread (Task.Run or StartNew) at all. It looks like the bulk of the work is I/O-bound and if you're doing it asynchronously and using Task.Delay instead of Thread.Sleep, then there is no thread consumed by those operations and your UI shouldn't freeze. The first thing anyone new to async needs to understand is that it's not the same thing as multithreading. The latter is all about consuming more threads, the former is all about consuming fewer. Focus on eliminating the blocking and you shouldn't need a second thread.
As others have noted, SeedingProd needs to return a Task, not void, so you can observe its completion. I believe your method can be reduced to this:
private async Task SeedingProd(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
foreach (var code in codesToSeed)
{
if (token.IsCancellationRequested)
return;
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
await Task.Dealy(30000);
}
}
Then simply call the method, without awaiting it, and you'll have your task.
Task mainTask = SeedingProd(token);
When you specify async on a method, it compiles into a state machine with a Task, so SeedingProd does not run synchronously, but acts as a Task even if returns void. So when you call Task.Factory.StartNew(SeedingProd) you start a task that kick off another task - that's why the first one finishes immediately before the second one. All you have to do is add the Task return parameter instead of void:
private async Task SeedingProdAsync(CancellationToken ct)
{
...
}
and call it as simply as this:
Task tskProdSeeding = SeedingProdAsync(_cts.Token);
The question describes the same problem found here - MSDN Developer Forum. The question does not have an accepted answer, neither any of the answers given can be applied to my case (hence a different question).
Question is also derived from one I asked previously, but, due to different nature and more specific problem, I'm asking a new one.
Full code can be found here: http://pastebin.com/uhBGWC5e
* Only thing changed is the task completion check (while -> Task.WhenAll).
When awaiting an async operation inside of a Task, the Task status changes to RanToCompletion even though, the Task is still running.
Now, let's see the setup:
// Start async.
Task t1 = Task.Factory.StartNew(Accept, s1);
Task t2 = Task.Factory.StartNew(Accept, s1);
Task.WhenAll(t1, t2).Wait();
The Accept method:
public static async void Accept(object state)
{
TcpListenerEx server = (TcpListenerEx) state;
IPEndPoint endPoint = server.LocalEndpoint as IPEndPoint;
Log("Accepting clients on {0}", endPoint);
while (true)
{
var client = server.AcceptTcpClientAsync();
if (client == null)
{
Log("Null error on accept");
break;
}
TcpClient connected = (TcpClient) client;
servers[server].Add(connected);
bool stop = await Task<Task<bool>>.Factory.StartNew(Listen, connected).Unwrap();
if (stop == true)
{
break;
}
}
// Stop the server.
server.Stop();
Log("Stoppped {0}", endPoint);
}
Because of TaskStatus changing to RanToCompletion, the Task.WhenAll().Wait() call marks itself finished fairly quickly, resulting in program to be executed further, eventually - terminated.
But, the Accept task, in theory, should never stop, it's listening for connections until explicitly stopped.
What is the problem here that's causing the Task to be marked as RanToCompletion prematurely?
I can reproduce this issue with far less code:
void Main()
{
Task t1 = Task.Factory.StartNew(Accept);
t1.Wait();
Console.WriteLine("Main ended");
}
public static async void Accept()
{
while (true)
{
await Task.Delay(1000);
}
Console.WriteLine("Stoppped");
}
But this works correctly:
void Main()
{
Task t1 = Accept();
t1.Wait();
Console.WriteLine("Main ended");
}
public static async Task Accept()
{
while (true)
{
await Task.Delay(1000);
}
Console.WriteLine("Stoppped");
}
Basically, by using Task.Factory.StartNew(), you are creating a Task based on a separate thread getting spawned to invoke the given delegate (the Accept() method). The Accept method itself (like any good async method) actually returns immediately. So the thread that calls it finishes its task immediately, so the Task created to represent that thread also finishes immediately.
If you allow Accept() to return a Task instead of void, then the Task that it returns is what you should be awaiting if you want to wait until it has run through all its awaits.
There are two things wrong: async void and Task.Factory.StartNew. Both of these are bad practices.
First, async void does not allow the calling code to know when it completes. So it doesn't matter that you're waiting; the async void method will return fairly quickly, and your app can't know when Accept actually finishes. To fix this, replace async void with the much more proper async Task.
Second, StartNew doesn't understand asynchronous delegates. StartNew is an extremely low-level API that should not be used in 99.99% of production code. Use Task.Run instead.
public static async Task Accept(object state);
Task t1 = Task.Run(() => Accept(s1));
Task t2 = Task.Run(() => Accept(s1));
Task.WaitAll(t1, t2);