I know there are a million questions on this and I am trying their solutions but it does not seem to behave as I would expect.
With the following code:
await Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");
I get the output:
[ 5 seconds elapses ]
I'm running after Thread.Sleep
I'm running after Task.Run
Which is the same output I would get without using Task.Run
What I want is the output:
I'm running after Task.Run
[ 5 seconds elapses ]
I'm running after Thread.Sleep
Where execution of the 'parent' thread continues and the long-running task is executed 'in the background' in a way which does not affect the 'parent' thread.
As mentioned you need to remove the await. However that turns it into a fire-and-forget task which, if the above code just happens to be in say a console app's Main then your process could terminate before the task has completed.
Good:
// C# 7
static async void Main(string[] args) // <--- note `async` signature
{
await Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running
after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");
}
Bad: - fire-and-forget task that isn't awaited
static void Main(string[] args)
{
Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("Spider Man: I don't wan't to go!"); }); // POOF!!
Console.WriteLine("I'm running after Task.Run");
// sorry Spidy, you're dead
}
So you might not see I'm running after Thread.Sleep at all even if you have a Thread.Sleep(). (by the way you should be using Task.Delay()). You could mitigate it with a Console.ReadKey() but that might defeat the purpose.
Fire-and-forget tasks have their uses, and can be used reasonably safely in other types of long-running apps like say WinForms but people generally don't go spawning Tasks in the process's entry point so the tasks generally run to completion without any early termination by the process. However, it's generally a good idea to use await where you can so you don't shoot yourself in the foot.
Also, your requirements of wanting things in a certain order sort of demonstrates a misunderstanding of how async/await works.
One thing to keep in mind when working with await is that your code awaits objects. These objects are just like any other objects. Specifically, they can be assigned to local variables or class variables.
So, this code:
await Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");
is essentially the same as this code:
var task = Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
await task;
Console.WriteLine("I'm running after Task.Run");
In other words:
Start a task running on a background thread.
Asynchronously wait (await) for that task to complete.
Display "I'm running after Task.Run".
So the output is expected.
What I want is the output:
I'm running after Task.Run
[ 5 seconds elapses ]
I'm running after Thread.Sleep
In that case, start the task running on the background thread, but don't await it until later:
var task = Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");
await task;
If you want to run asynchronously you should remove the command away
static void Main(string[] args)
{
Task.Run(() => { Thread.Sleep(5000); Console.WriteLine(DateTime.Now + " => I'm running after Thread.Sleep"); });
Console.WriteLine(DateTime.Now + " => I'm running after Task.Run");
while (true)
{
Thread.Sleep(500);
}
}
Output
28/05/2019 09:49:58 => I'm running after Task.Run
28/05/2019 09:50:03 => I'm running after Thread.Sleep
Related
We have a project where we run some tasks in parallel. We are starting Tasks to do this. Every Task runs a code inside a CodeDom (written by customer to customize part of the process). It works fine.
I would like to know how to limitate the time of the execution of a Task. I am afraid of the user write a bad code and it result in something like infinity loop or a bad code which takes a lot of time to perform. I would like to give him 10 seconds to perform its code and after that, kill the thread that is running on the Task and finish the Task.
For sample (pseudo code):
Task[] tasks = GetListOfTasks();
foreach (var task in tasks)
{
task.Start();
}
I tried to do this:
Task.WaitAll(tasks, TimeSpan.FromSeconds(10));
I already have the cancelation token on all these tasks, but the user can't use it.
How can I stop the task execution and kill the tasks if it do not finish on the specified TimeSpan ?
Thank you.
var threadTask = Task.Run(() =>
{
// start thread
thread.Start();
// force to wait the thread
thread.Join();
});
// run a new task to wait the task/thread to finish in a timeout.
// on the continueWith, abort the thread.
Task.Run(() => Task.WaitAll(new[] { threadTask }, TimeSpan.FromSeconds(10)))
.ContinueWith(t =>
{
if (thread.IsAlive)
{
thread.Abort();
}
});
I want to pause the program so it does not close. I have a code running in the main thread. Tried this way, but this code instantly skips and the program closes instead of waiting.
How can I make it wait for the WaitMy method to complete?
static void Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
WaitMy();
}
private async static void WaitMy()
{
//await Task.Delay(30 * 1000);
await Task.Run(async () => await Task.Delay(30 * 1000));
}
The application runs with .net 4.5.
Change the code to following to make it work:
static async Task Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
await WaitMy();
}
How this works ?
You need C# 7.1 or later versions
Now Main method can be declared async and has return type as Task for introducing await
It will simply let the delay execute asynchronously, but will renter the main context for continuation, which will not exit
Another suggestion would be, you just need await Task.Delay(30 * 1000), wrapping inside the Task.Run is not required here
You are using Task Programming Library. What happens here is that, in your WaitMy method, you are scheduling a task to be executed (await Task.Run(...)). The task is being executed on a background thread.
In the meanwhile, the Main method continues its execution after the call to the WaitMy method.
The Main method ends right after, so the foreground thread is terminated, and all the background threads associated to its process are terminated too.
If you just want to perform a delay, just use:
System.Threading.Thread.Sleep(30 * 1000);
in the Main method, instead of calling WaitMy.
The method WaitMy can return a Task instance so you can have your main thread wait for it to be completed.
static void Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
var task = WaitMy();
task.Wait();
Console.WriteLine("And done :)");
}
private static Task WaitMy()
{
//await Task.Delay(30 * 1000);
return Task.Run(async () => await Task.Delay(30 * 1000));
}
If you just want the program to wait before terminating a simple answer would be to use
Console.ReadKey();
If you are curious why program terminates without waiting it is because you delegate waiting to ThreadPool by using Task.Run so waiting occurs on another thread an your application simply terminates before it can receive any result from ThreadPool
I've the following code:
static void Main(string[] args)
{
IEnumerable<int> threadsIds = Enumerable.Range(1, 1000);
DateTime globalStart = DateTime.Now;
Console.WriteLine("{0:s.fff} Starting tasks", globalStart);
Parallel.ForEach(threadsIds, (threadsId) =>
{
DateTime taskStart = DateTime.Now;
const int sleepDuration = 1000;
Console.WriteLine("{1:s.fff} Starting task {0}, sleeping for {2}", threadsId, taskStart, sleepDuration);
Thread.Sleep(sleepDuration);
DateTime taskFinish = DateTime.Now;
Console.WriteLine("{1:s.fff} Ending task {0}, task duration {2}", threadsId, taskFinish, taskFinish- taskStart);
});
DateTime globalFinish= DateTime.Now;
Console.WriteLine("{0:s.fff} Tasks finished. Total duration: {1}", globalFinish, globalFinish-globalStart);
Console.ReadLine();
}
Currently when I run it, it takes ~60seconds to run it. For what I understand, it's because .Net doesn't create one thread per task but some threads for all the Tasks, and when I do the Thread.Sleep, I prevent this thread to execute some other tasks.
In my real case, I've some work to do in parallel, and in case of failure, I've to wait some amount of time before trying again.
I'm looking something else than the Thread.Sleep, that would allow other tasks to run during the "sleep time" of other tasks.
Unfortunately, I'm currently running .Net 4, which prevent me to use async and await(which I guess could have helped me in this case.
Ps, I got the same results by:
putting Task.Delay(sleepDuration).Wait()
Not using Parallel.Foreach, but a foreach with a Task.Factory.StartNew
Ps2, I know that I can do my real case differently, but I'm very interessted to understand how it could be achieved that way.
You are on the right path. Task.Delay(timespan) is the solution for your problem. Since you cannot use async/await, you have to write a bit more code to achieve the desired result.
Think about using Task.ContinueWith() method, for example:
Task.Run(() => { /* code before Thread.Sleep */ })
.ContinueWith(task => Task.Delay(sleepDuration)
.ContinueWith(task2 => { /* code after Thread.Sleep */ }));
Also you will need create a class to make local method variables accessible across subtasks.
If you want to create a task that will run polling every second some condition, you could try the following code:
Task PollTask(Func<bool> condition)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
PollTaskImpl(tcs, condition);
return tcs.Task;
}
void PollTaskImpl(TaskCompletionSource<bool> tcs, Func<bool> condition)
{
if (condition())
tcs.SetResult(true);
else
Task.Delay(1000).ContinueWith(_ => PollTaskImpl(tcs, condition));
}
Don't worry about creating new task every second - ContinueWith and async/await methods do the same thing internally.
I was reading about SynchronizationContext and its use with the async/await methods (link). From my understanding, in a Console application where the SynchronizationContext is null, the continuation of an awaited method (Task) will be scheduled with the default scheduler which would be the ThreadPool.
But if I run this console app, you'll see from the output that the the continuation is run on the worker thread that I created:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("MainThreadId=" + Thread.CurrentThread.ManagedThreadId);
Method1().ContinueWith(t =>
{
Console.WriteLine("After Method1. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
});
Console.ReadKey();
}
public static async Task Method1()
{
Console.WriteLine("Method1 => Entered. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>();
Thread thread = new Thread(() =>
{
Console.WriteLine("Method1 => Started new thread. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(2000);
completionSource.SetResult(true);
});
thread.Start();
await completionSource.Task;
Console.WriteLine("Method1 => After WorkerThread. ThreadId=" + Thread.CurrentThread.ManagedThreadId);
}
}
And here is the output:
MainThreadId=10
Method1 => Entered. ThreadId=10
Method1 => Started new thread. ThreadId=11
Method1 => After WorkerThread. ThreadId=11
After Method1. ThreadId=12
As you can see, "After WorkerThread" was outputted on the same thread as my workerthread, but not on the threadpool.
I found a similar question but the guy was using Mono and they were saying that this was a bug. On my side, I built this code with in Visual Studio and ran it under Windows 7 and .Net 4.5.2 installed on my machine.
Could someone please explain this behaviour?
It's because of an implementation detail that I documented on my blog: the continuation created by await is scheduled using the ExecuteSynchronously flag. In that case, when it is time to fire the continuation (i.e., in the TaskCompletionSource<T>.SetResult call on the worker thread), the default scheduler first attempts to determine whether it can run on the current thread.
Since the worker thread has no TaskScheduler that will reject executing the task synchronously, the ExecuteSynchronously flag will cause the thread pool task scheduler to just execute the task synchronously (i.e., on the calling thread).
Given the following code...
static void DoSomething(int id) {
Thread.Sleep(50);
Console.WriteLine(#"DidSomething({0})", id);
}
I know I can convert this to an async task as follows...
static async Task DoSomethingAsync(int id) {
await Task.Delay(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
}
And that by doing so if I am calling multiple times (Task.WhenAll) everything will be faster and more efficient than perhaps using Parallel.Foreach or even calling from within a loop.
But for a minute, lets pretend that Task.Delay() does not exist and I actually have to use Thread.Sleep(); I know in reality this is not the case, but this is concept code and where the Delay/Sleep is would normally be an IO operation where there is no async option (such as early EF).
I have tried the following...
static async Task DoSomethingAsync2(int id) {
await Task.Run(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
But, though it runs without error, according to Lucien Wischik this is in fact bad practice as it is merely spinning up threads from the pool to complete each task (it is also slower using the following console application - if you swap between DoSomethingAsync and DoSomethingAsync2 call you can see a significant difference in the time that it takes to complete)...
static void Main(string[] args) {
MainAsync(args).Wait();
}
static async Task MainAsync(String[] args) {
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 1000; i++)
tasks.Add(DoSomethingAsync2(i)); // Can replace with any version
await Task.WhenAll(tasks);
}
I then tried the following...
static async Task DoSomethingAsync3(int id) {
await new Task(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
Transplanting this in place of the original DoSomethingAsync, the test never completes and nothing is shown on screen!
I have also tried multiple other variations that either do not compile or do not complete!
So, given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task, how do you do it in a manner that is as efficient as the original code?
The objective here for those of you who are interested is to give me a better understanding of how to create my own async methods where I am not calling anybody elses. Despite many searches, this seems to be the one area where examples are really lacking - whilst there are many thousands of examples of calling async methods that call other async methods in turn I cannot find any that convert an existing void method to an async task where there is no call to a further async task other than those that use the Task.Run(() => {} ) method.
There are two kinds of tasks: those that execute code (e.g., Task.Run and friends), and those that respond to some external event (e.g., TaskCompletionSource<T> and friends).
What you're looking for is TaskCompletionSource<T>. There are various "shorthand" forms for common situations so you don't always have to use TaskCompletionSource<T> directly. For example, Task.FromResult or TaskFactory.FromAsync. FromAsync is most commonly used if you have an existing *Begin/*End implementation of your I/O; otherwise, you can use TaskCompletionSource<T> directly.
For more information, see the "I/O-bound Tasks" section of Implementing the Task-based Asynchronous Pattern.
The Task constructor is (unfortunately) a holdover from Task-based parallelism, and should not be used in asynchronous code. It can only be used to create a code-based task, not an external event task.
So, given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task, how do you do it in a manner that is as efficient as the original code?
I would use a timer of some kind and have it complete a TaskCompletionSource<T> when the timer fires. I'm almost positive that's what the actual Task.Delay implementation does anyway.
So, given the constraint that you cannot call any existing
asynchronous methods and must complete both the Thread.Sleep and the
Console.WriteLine in an asynchronous task, how do you do it in a
manner that is as efficient as the original code?
IMO, this is a very synthetic constraint that you really need to stick with Thread.Sleep. Under this constraint, you still can slightly improve your Thread.Sleep-based code. Instead of this:
static async Task DoSomethingAsync2(int id) {
await Task.Run(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
You could do this:
static Task DoSomethingAsync2(int id) {
return Task.Run(() => {
Thread.Sleep(50);
Console.WriteLine(#"DidSomethingAsync({0})", id);
});
}
This way, you'd avoid an overhead of the compiler-generated state machine class. There is a subtle difference between these two code fragments, in how exceptions are propagated.
Anyhow, this is not where the bottleneck of the slowdown is.
(it is also slower using the following console application - if you
swap between DoSomethingAsync and DoSomethingAsync2 call you can see a
significant difference in the time that it takes to complete)
Let's look one more time at your main loop code:
static async Task MainAsync(String[] args) {
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 1000; i++)
tasks.Add(DoSomethingAsync2(i)); // Can replace with any version
await Task.WhenAll(tasks);
}
Technically, it requests 1000 tasks to be run in parallel, each supposedly to run on its own thread. In an ideal universe, you'd expect to execute Thread.Sleep(50) 1000 times in parallel and complete the whole thing in about 50ms.
However, this request is never satisfied by the TPL's default task scheduler, for a good reason: thread is a precious and expensive resource. Moreover, the actual number of concurrent operations is limited to the number of CPUs/cores. So in reality, with the default size of ThreadPool, I'm getting 21 pool threads (at peak) serving this operation in parallel. That is why DoSomethingAsync2 / Thread.Sleep takes so much longer than DoSomethingAsync / Task.Delay. DoSomethingAsync doesn't block a pool thread, it only requests one upon the completion of the time-out. Thus, more DoSomethingAsync tasks can actually run in parallel, than DoSomethingAsync2 those.
The test (a console app):
// https://stackoverflow.com/q/21800450/1768303
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Console_21800450
{
public class Program
{
static async Task DoSomethingAsync(int id)
{
await Task.Delay(50);
UpdateMaxThreads();
Console.WriteLine(#"DidSomethingAsync({0})", id);
}
static async Task DoSomethingAsync2(int id)
{
await Task.Run(() =>
{
Thread.Sleep(50);
UpdateMaxThreads();
Console.WriteLine(#"DidSomethingAsync2({0})", id);
});
}
static async Task MainAsync(Func<int, Task> tester)
{
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 1000; i++)
tasks.Add(tester(i)); // Can replace with any version
await Task.WhenAll(tasks);
}
volatile static int s_maxThreads = 0;
static void UpdateMaxThreads()
{
var threads = Process.GetCurrentProcess().Threads.Count;
// not using locks for simplicity
if (s_maxThreads < threads)
s_maxThreads = threads;
}
static void TestAsync(Func<int, Task> tester)
{
s_maxThreads = 0;
var stopwatch = new Stopwatch();
stopwatch.Start();
MainAsync(tester).Wait();
Console.WriteLine(
"time, ms: " + stopwatch.ElapsedMilliseconds +
", threads at peak: " + s_maxThreads);
}
static void Main()
{
Console.WriteLine("Press enter to test with Task.Delay ...");
Console.ReadLine();
TestAsync(DoSomethingAsync);
Console.ReadLine();
Console.WriteLine("Press enter to test with Thread.Sleep ...");
Console.ReadLine();
TestAsync(DoSomethingAsync2);
Console.ReadLine();
}
}
}
Output:
Press enter to test with Task.Delay ...
...
time, ms: 1077, threads at peak: 13
Press enter to test with Thread.Sleep ...
...
time, ms: 8684, threads at peak: 21
Is it possible to improve the timing figure for the Thread.Sleep-based DoSomethingAsync2? The only way I can think of is to use TaskCreationOptions.LongRunning with Task.Factory.StartNew:
You should think twice before doing this in any real-life application:
static async Task DoSomethingAsync2(int id)
{
await Task.Factory.StartNew(() =>
{
Thread.Sleep(50);
UpdateMaxThreads();
Console.WriteLine(#"DidSomethingAsync2({0})", id);
}, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
}
// ...
static void Main()
{
Console.WriteLine("Press enter to test with Task.Delay ...");
Console.ReadLine();
TestAsync(DoSomethingAsync);
Console.ReadLine();
Console.WriteLine("Press enter to test with Thread.Sleep ...");
Console.ReadLine();
TestAsync(DoSomethingAsync2);
Console.ReadLine();
}
Output:
Press enter to test with Thread.Sleep ...
...
time, ms: 3600, threads at peak: 163
The timing gets better, but the price for this is high. This code asks the task scheduler to create a new thread for each new task. Do not expect this thread to come from the pool:
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
Console.WriteLine("Thread pool: " +
Thread.CurrentThread.IsThreadPoolThread); // false!
}, TaskCreationOptions.LongRunning).Wait();