How to Put a Task to Sleep (Or Delay) in C# 4.0

How to put a task to sleep (or delay) in C# 4.0?

You can use a Timer to create a Delay method in 4.0:

public static Task Delay(double milliseconds)
{
var tcs = new TaskCompletionSource<bool>();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed+=(obj, args) =>
{
tcs.TrySetResult(true);
};
timer.Interval = milliseconds;
timer.AutoReset = false;
timer.Start();
return tcs.Task;
}

Tasks on Framework 4.0: Put a timeout on the innermost task in a chain of continuations

You can try to create task with CancellationToken and then call tokenSource.CancelAfter(...) like this

var tokeSource = new CancellationTokenSource();
Task.Run(() => { Console.WriteLine("processing"); }, tokenSource.Token);
tokenSource.CancelAfter(TimeSpan.FromSeconds(30));

In .Net 4.0 you can implement CancelAfter by yourself with something like

public static class CancellationTokenSourceExtensions
{
public static Task CancelAfter(this CancellationTokenSource cts, TimeSpan timeout)
{
return Task.Delay(timeout).ContinueWith(t => cts.Cancel());
}
}

I personally think that cts-based solution is more with the spirit of TPL.

When to use Task.Delay, when to use Thread.Sleep?

Use Thread.Sleep when you want to block the current thread.

Use await Task.Delay when you want a logical delay without blocking the current thread.

Efficiency should not be a paramount concern with these methods. Their primary real-world use is as retry timers for I/O operations, which are on the order of seconds rather than milliseconds.

Diference between task.wait , Task.delay and thread.sleep

Basically Wait() and Sleep() are both thread blocking operations,in other words they force a thread to sit idle instead of doing work elsewhere. Delay on other hand uses a timer internally that releases the thread in use until the delay is complete.

There is much more that can be said about these three functions so here's a small sample set for further reading.

More Info

  • There is no thread
  • Don't Block on Async Code
  • When to use Task.Delay, when to use Thread.Sleep?
  • Thread.Sleep vs Task.Delay?
  • Thread.Sleep is a sign of a poorly designed program.

public class WaitSleepDelay
{
/// <summary>
/// The thread is released and is alerted when the delay finishes
/// </summary>
/// <returns></returns>
public async Task Delay()
{
//This Code Executes
await Task.Delay(1000);
//Now this code runs after 1000ms
}

/// <summary>
/// This blocks the currently executing thread for the duration of the delay.
/// This means that the thread is held hostage doing nothing
/// instead of being released to do more work.
/// </summary>
public void Sleep()
{
//This Code Executes
Thread.Sleep(1000);
//Now this code runs after 1000ms
}

/// <summary>
/// This blocks the currently executing thread for the duration of the delay
/// and will deadlock in single threaded sync context e.g. WPF, WinForms etc.
/// </summary>
public void Wait()
{
//This Code Executes
Task.Delay(1000).Wait();
//This code may never execute during a deadlock
}
}

Call Thread.Sleep from the Task

You can use Thread.Sleep inside a task.
But in most situations I'd prefer to use await Task.Delay which does not block the thread.

If you're using Task.Run (which uses a ThreadPool thread), then you should try not to block the thread. As it is a shared thread, there may be other code waiting to run.

I would still use Thread.Sleep(0) when I'm done using the thread, to yield the processor and give up your time slice.

Thread.Sleep vs Task.Delay?

The documentation on MSDN is disappointing, but decompiling Task.Delay using Reflector gives more information:

public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
{
if (millisecondsDelay < -1)
{
throw new ArgumentOutOfRangeException("millisecondsDelay", Environment.GetResourceString("Task_Delay_InvalidMillisecondsDelay"));
}
if (cancellationToken.IsCancellationRequested)
{
return FromCancellation(cancellationToken);
}
if (millisecondsDelay == 0)
{
return CompletedTask;
}
DelayPromise state = new DelayPromise(cancellationToken);
if (cancellationToken.CanBeCanceled)
{
state.Registration = cancellationToken.InternalRegisterWithoutEC(delegate (object state) {
((DelayPromise) state).Complete();
}, state);
}
if (millisecondsDelay != -1)
{
state.Timer = new Timer(delegate (object state) {
((DelayPromise) state).Complete();
}, state, millisecondsDelay, -1);
state.Timer.KeepRootedWhileScheduled();
}
return state;
}

Basically, this method is just a timer wrapped inside of a task. So yes, you can say it's just like timer.

Is Task.Delay undocumented in .NET 4?

This method does not exist in .NET 4.0.

You are probably ILspying 4.5. All of .NET 4.x's assemblies, through 4.5.2 at the time of this post, show v4.0.0.0, and newer versions replace older versions when you install them -- they're made to be backward compatible.

When you are able to grab Task.Delay through reflection, it's because your app is actually running on .NET 4.5.

When you select a framework version in Visual Studio, it will use whatever version you have installed, but only show the methods actually in that selection -- you can think of it as a compatibility selection, not so much an exact version selection.

I believe one of the Microsoft.Bcl and Microsoft.Bcl.Async packages on NuGet contains a TaskEx.Delay you can use which will emulate it on older frameworks and route to the build-in version when used on newer ones. These packages contain back-ported APIs.



Related Topics



Leave a reply



Submit